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
相关产品推荐
相关产品推荐

