You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中std::string::erase()误删空格及连续感叹号删除问题咨询

解决std::string::erase()误删字符及批量删除感叹号的问题

问题描述

要实现删除字符串中所有感叹号!的功能,但使用std::string::erase()时出现两个异常:

  • 误删空格:测试字符串"Hi! Hello!"处理后先变成"HiHello!",最终变为"HiHello",空格被意外删除;
  • 一次性删除连续感叹号:字符串"Hello World!!!"直接变成"Hello World",没有依次经历"Hello World!!"和"Hello World!"的过程。

错误原因

核心问题是混淆了std::string::erase()的两种重载参数逻辑:

  • 你调用的是erase(size_t pos, size_t count)版本:第二个参数是要删除的字符数量,不是结束位置;
  • 你错误地将pos + remove.length()作为第二个参数传入,导致每次删除的字符数远大于1(比如第一个!在位置2时,传入的count是3),直接删掉了!后面的多个字符(包括空格);
  • 对于连续的!!!,第一次找到第一个!的位置后,传入的count值超过了剩余字符串长度,直接删除了从该位置到末尾的所有字符,所以一次性删完所有连续!。

修正方案

方案1:修正erase的参数传递

将第二个参数改为要删除的字符数(即感叹号的长度remove.length()),这样每次只删除找到的单个!:

#include <string>

std::string removeExclamationMarks(std::string str){
    std::string remove{ "!" };
    std::cerr << str << '\n';
    size_t pos{};
    while( (pos = str.find(remove)) != std::string::npos ){
        std::cerr << pos << '\n';
        // 第二个参数改为要删除的字符数,不是结束位置
        str.erase(pos, remove.length());
        std::cerr << str << '\n';
    }
    std::cerr << "END\n";
    return str;
}

方案2:使用迭代器版本的erase

如果你习惯用起始+结束位置的逻辑,可以改用迭代器重载版本,符合左闭右开的区间规则:

str.erase(str.begin() + pos, str.begin() + pos + remove.length());

方案3:更高效的erase-remove惯用法(推荐)

C++中删除容器内特定元素的标准高效写法,无需循环查找,一次性处理所有!:

#include <string>
#include <algorithm>

std::string removeExclamationMarks(std::string str){
    // std::remove将所有!移到字符串末尾,返回第一个!的迭代器
    auto exclamPos = std::remove(str.begin(), str.end(), '!');
    // 删除从该迭代器到末尾的所有字符
    str.erase(exclamPos, str.end());
    return str;
}

内容的提问来源于stack exchange,提问作者F. Andrés

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 20:05:14