C++删除字符串上的标点符号,擦除()/迭代器问题
C++ removing punctuation on strings, erase()/iterator issue
我知道我不是第一个提出反向迭代器试图在字符串上调用erase()方法的人。但是,我找不到任何解决此问题的好方法。
我正在阅读一个文件的内容,其中包含一堆单词。当我读到一个单词时,我想把它传递给一个我称之为stripPunct的函数。但是,我只想在字符串的开头和结尾去除标点符号,而不是中间。
例如:
(单词)应去除"("和")",结果为单词
不要!应该去掉"!"导致只是不要
所以我的逻辑(我相信可以改进)是有两个 while 循环,一个从末尾开始,一个从开头开始,遍历和擦除,直到它到达非标点符号字符。
void stripPunct(string & str) {
string::iterator itr1 = str.begin();
string::reverse_iterator itr2 = str.rbegin();
while ( ispunct(*itr1) ) {
str.erase(itr1);
itr1++;
}
while ( ispunct(*itr2) ) {
str.erase(itr2);
itr2--;
}
}
但是,显然它不起作用,因为 erase() 需要一个常规迭代器而不是reverse_iterator。但无论如何,我觉得这种逻辑效率很低。
另外,我尝试仅使用常规迭代器代替reverse_iterator,从str.end()开始,然后递减它,但是它说如果我在str.end()启动它,我无法取消引用迭代器。
谁能帮我找到一个好方法?或者也许指出我已经拥有的解决方法?
提前非常感谢!
------------------ [ 编辑 ] ----------------------------
找到了一个解决方案,尽管它可能不是最好的解决方案:
// Call the stripPunct method:
stripPunct(str);
if ( !str.empty() ) { // make sure string is still valid
// perform other code
}
这是 stripPunct 方法:
void stripPunct(string & str) {
string::iterator itr1 = str.begin();
string::iterator itr2 = str.end();
while ( !(str.empty()) && ispunct(*itr1) )
itr1 = str.erase(itr1);
itr2--;
if ( itr2 != str.begin() ) {
while ( !(str.empty()) && ispunct(*itr2) ) {
itr2 = str.erase(itr2);
itr2--;
}
}
}
首先,请注意代码的几个问题:
- 使用
itr1
调用erase()
后,您已使itr2
无效。 - 当使用
reverse_iterator
向后浏览序列时,您希望使用++
,而不是--
(这就是反向迭代器存在的原因)。
现在,为了改进逻辑,您可以通过找到第一个您不想擦除的角色来避免单独擦除每个字符,并擦除到那时的所有内容。 find_if()
可用于帮助:
int not_punct(char c) {
return !ispunct((unsigned char) c);
}
void stripPunct(string & str) {
string::iterator itr = find_if( str.begin(), str.end(), not_punct);
str.erase( str.begin(), itr);
string::reverse_iterator ritr = find_if( str.rbegin(), str.rend(), not_punct);
str.erase( ritr.base(), str.end());
}
请注意,我使用 base()
来获取与reverse_iterator
对应的"常规"迭代器。 我发现是否需要调整base()
逻辑令人困惑(反向迭代器通常会让我感到困惑)——在这种情况下,它不是因为我们碰巧想在找到的角色之后开始擦除。
http://drdobbs.com/cpp/184401406 斯科特·迈耶斯(Scott Meyers)的这篇文章很好地处理了本节中的reverse_iterator::base()
。"准则 3:了解如何使用reverse_iterator的基础迭代器"。 该文章中的信息也被纳入了Meyer的"Effective STL"一书中。
你不能取消引用迭代器::end(),因为它指向无效内存(数组末尾之后的内存),所以你必须首先递减它。
最后一点:如果单词仅由标点符号组成,您的程序将失败,请务必处理。
如果你不介意负逻辑,你可以执行以下操作:
string tmp_str="";
tmp_str.reserve(str.length());
for (string::iterator itr1 = str.begin(); itr1 != str.end(); itr1++)
{
if (!ispunct(*itr1))
{
tmp_str.push_back(*itr1);
}
}
str = tmp_str;
- ESP8266单片机矢量迭代器的C++问题
- 成员函数中的迭代器出现问题
- 迭代器的指针操作问题
- 为什么在这个C++问题中使用const_iterator而不仅仅是迭代器?
- std::filesystem::directory_迭代器链接器问题(C++17)
- 使用 find() 通过 std::set 的迭代器将不起作用。出了什么问题?
- 无法取消引用超出范围的向量迭代器 - 有什么问题?
- 调用模板函数的问题"No matching function for call"参数:迭代器、对象函数
- 迭代器的问题
- 无法理解迭代器的问题?
- 对于循环迭代器问题 c++
- 将MAP与一对用作C 迭代器问题中的键
- C++字符串的迭代器问题
- 模板变量作为unordered_map键,迭代器问题
- 映射迭代器问题.包括代码
- 链接列表帮助,迭代器问题
- 仅visual studio 2010中存在可延迟迭代器问题
- 向列表添加项和迭代器问题
- C++ 提升::p tr_vector<S>::迭代器问题
- C++删除字符串上的标点符号,擦除()/迭代器问题