我知道我不是第一个提出反向迭代器试图在字符串上调用erase()方法的人。但是,我无法找到任何好方法。
我正在读取文件的内容,其中包含一堆单词。当我读到一个单词时,我想将它传递给我称为stripPunct的函数。但是,我只想在字符串的开头和结尾处去除标点符号,而不是在中间。
例如:
(word)应该删除'('和')',结果只是 word
不要!应该删除'!'导致只是不
所以我的逻辑(我肯定可以改进)是有两个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()启动它就不能取消引用迭代器。 / p>
任何人都可以帮我一个好方法吗?或者可能指出我已有的解决方法?
提前非常感谢你!
------------------ [编辑] -------------------------- -
找到了解决方案,虽然它可能不是最好的解决方案:
// 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--;
}
}
}
答案 0 :(得分:4)
首先,请注意代码中的几个问题:
erase()
致电itr1
后,您已将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()
是否需要调整混乱的逻辑(反向迭代器一般让我感到困惑) - 在这种情况下它不会因为我们碰巧想要在找到的字符后开始擦除。
Scott Meyers撰写的这篇文章http://drdobbs.com/cpp/184401406在本节中对reverse_iterator::base()
进行了很好的处理。 “准则3:了解如何使用reverse_iterator的基础迭代器”。该文章中的信息也已纳入迈耶的“有效STL”一书中。
答案 1 :(得分:0)
你不能解除引用iterator :: end()因为它指向无效的内存(数组结束后的内存),所以你必须先减少它。
最后一点说明:如果这个单词只包含标点符号,那么你的程序就会失败,请务必处理。
答案 2 :(得分:0)
如果您不介意否定逻辑,则可以执行以下操作:
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;