std :: string擦除最后一个字符失败?

时间:2008-10-23 19:38:13

标签: c++ string

我正在尝试将通配符格式("*word*")中的用户输入更改为正则表达式格式。为此,我使用下面的代码在输入的开头和结尾处去除'*',以便我可以在任一端添加正则表达式字符:

string::iterator    iter_begin = expressionBuilder.begin();
string::iterator    iter_end = expressionBuilder.end();
iter_end--;
if ((char)*iter_begin == '*' && (char)*iter_end == '*')
{
    expressionBuilder.erase(iter_begin);
    expressionBuilder.erase(iter_end);
    expressionBuilder = "\\b\\w*" + expressionBuilder + "\\w*\\b";
}

然而,对"expressionBuilder.erase(iter_end)"的调用从输入字符串中删除尾随的'*',所以最终会出现错误的正则表达式。我在这做错了什么?对于要运行的if语句中的代码,"(char)*iter_end == '*'"必须为true(它确实如此),那么为什么传递给erase()时同一个迭代器不起作用?

4 个答案:

答案 0 :(得分:7)

到目前为止,您的原始代码和建议的解决方案除了您发布的明显问题外还有一些问题:

  • 修改字符串后使用无效的迭代器
  • 甚至在修改字符串之前解除引用可能无效的迭代器(例如,如果字符串为空)
  • 如果expressionBuilder字符串只包含一个'*'字符
  • ,则会出现错误

现在,如果使用代码段/例程的代码已经验证字符串至少有2个字符,那么最后两个项目可能不是真正的问题,但是如果不是这种情况,我相信以下内容面对expressionBuilder的任意值更加健壮:

// using the reverse iterator rbegin() is a nice easy way 
//     to get the last character of a string

if ( (expressionBuilder.size() >= 2) &&
    (*expressionBuilder.begin()  == '*') &&
    (*expressionBuilder.rbegin() == '*') ) {

    expressionBuilder.erase(expressionBuilder.begin());

    // can't nicely use rbegin() here because erase() wont take a reverse
    //  iterator, and converting reverse iterators to regular iterators
    //  results in rather ugly, non-intuitive code
    expressionBuilder.erase(expressionBuilder.end() - 1); // note - not invalid since we're getting it anew

    expressionBuilder = "\\b\\w*" + expressionBuilder + "\\w*\\b";
}

请注意,当expressionBuilder"""*""**"时,此代码将起作用,因为它不会执行任何未定义的操作。但是,在这些情况下,它可能无法产生您想要的结果(因为我不确切知道在这些情况下您想要的是什么)。修改以满足您的需求。

答案 1 :(得分:3)

尝试以相反的顺序擦除它们:

expressionBuilder.erase(iter_end);
expressionBuilder.erase(iter_begin);

在删除第一个*后,iter_end引用示例中字符串末尾之后的一个字符。 STL documentation表示迭代器被erase()无效,所以从技术上来说,我的例子也是错误的,但我相信它会在实践中发挥作用。

答案 2 :(得分:1)

(修改后,因为我错过了iter_end--行)。

您可能想要一个只检查*iter_begin == '*'的if语句,然后调用find()来获取另一个'*'。或者您可以使用rbegin()来获取“反向序列的开始迭代器”,将其前进一个然后调用base()将其转换为常规迭代器。这将使你获得序列中的最后一个字符。


更好的是,std::stringrfind() and find_last_of() methods。他们会告诉你最后'*'。您也可以简单地拨打replace()而不是删除'*',然后重新添加新内容。

答案 3 :(得分:0)

减少错误处理,你可能会这样做:

#include <iostream>
#include <string>
using namespace std;

string stripStar(const string& s) {
    return string(s.begin() + 1, s.end() - 1);
}

int main() {
   cout << stripStar("*word*") << "\n";
}