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

std::string erase last character fails?

本文关键字:字符 失败 最后一个 擦除 string std      更新时间:2023-10-16

我正在尝试将通配符形式("*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()时不起作用呢?

除了您发布的关于的明显问题外,您的原始代码和迄今为止提出的解决方案还有几个问题:

  • 修改字符串后使用无效迭代器
  • 甚至在修改字符串之前就取消引用可能无效的迭代器(例如,如果字符串为空)
  • 如果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"""*""**"时,此代码将起作用,因为它不执行任何未定义的操作。然而,在这些情况下,它可能不会产生你想要的结果(这是因为我不知道你在这些情况中到底想要什么)。修改以满足您的需求。

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

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

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

(已修订,因为我错过了iter_end--行)。

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


更好的是,std::string具有rfind()find_last_of()方法。他们会给你最后一个'*'。您也可以简单地调用replace(),而不是剥离'*',然后将新的东西添加回。

减去错误处理,您可能只需要这样做:

#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";
}