在字符串中删除分隔符之间的字符

3
我想删除字符串中两个相同字符之间的所有字符。我的函数在其参数中接受一个字符串(按引用传递)和一个字符。
假设我使用了像这样的std :: string变量作为第一个参数:“hah haaah hah hello!”并使用字符'h'作为第二个参数,应该会发生以下情况:“hah haaah hah hello!” ===>“hh hh hh hello”。正如您所看到的,已经删除了两个'h'字符之间的每个字符。我该如何实现这样的效果?
我尝试使用迭代器,并得到了以下结果:
void delete_chars_between(std::string& line, char del)
{
    std::string::iterator itr_from = std::find(line.begin(), line.end(), del);
    std::string::iterator itr_to = std::find(itr_from + 1, line.end(), del);

    while (true) {
        if(itr_to != line.end())
            line.erase(itr_from + 1, itr_to);

        itr_from = std::find(itr_to, line.end(), del);

        if (itr_from == line.end())
            break;

        itr_to = std::find(itr_from + 1, line.end(), del);

        if (itr_to == line.end())
            break;
    }
}

首先,我搜索第一个出现的del,并将其位置的迭代器存储在itr_from中。之后,我搜索第二个del的出现。最后,如果itr_to有效,我会运行一个while循环,该循环从一定范围内删除字符。只要我的迭代器不等于line.end(),我就一遍又一遍地重复这个过程。
但由于某些原因,这段代码无法正常工作。有时它会删除空格,甚至不会触及我想要删除的字符。
感谢您的帮助。

1
我在想这里是否更适合使用std::regex_replace - NathanOliver
@NathanOliver,不幸的是我还不知道如何使用正则表达式。我真的想在不使用它的情况下实现我的目标。 - Michael
也许首先将输入按空格拆分为字符串数组会更容易,就像这样:https://dev59.com/k3VC5IYBdhLWcg3wnCj6? - Leo Chapiro
迭代器可能会被erase使无效,尝试在erase操作后重置两者。 - Matt
如果您将输入字符串视为字符数组,那么可以简单地按字符遍历它,从复制模式开始,并针对每个字符进行复制或忽略操作,将其附加到新的空字符串中。如果遇到分隔符字符,只需在模式之间切换(但无论如何都要附加分隔符字符)。 - Ped7g
2个回答

3

std::string的迭代器会在所有修改字符串长度的操作中失效,因此在调用line.erase后使用itr_fromitr_to是未定义行为。

您需要使用erase的返回值:

while (true) {
    if(itr_to != line.end())
        itr_to = line.erase(itr_from + 1, itr_to);

    itr_from = std::find(itr_to, line.end(), del);

    if (itr_from == line.end())
        break;

    itr_to = std::find(itr_from + 1, line.end(), del);

    if (itr_to == line.end())
        break;
}

0
为避免未定义的行为,在调用erase之前,应重置两个迭代器。
从预期输出来看,似乎不应使用关闭分隔符来开始另一个区间:
"hh hh hh hello"  not  "hhhhhhhello"
   ^  ^  ^

所以,这是我的建议:

void delete_chars_between(std::string& line, char del)
{
    std::string::iterator itr_from = std::find(line.begin(), line.end(), del);
    // I don't want to pass an iterator to two past the last element
    if ( itr_from == line.end() )
        return; 
    std::string::iterator itr_to = std::find(itr_from + 1, line.end(), del);
    //                                               ^^^^

    while ( itr_to != line.end() )
    {
        itr_to = line.erase(itr_from + 1, itr_to);

        itr_from = std::find(itr_to + 1, line.end(), del);
        // to start another couple ^^^^
        if (itr_from == line.end())
            break;

        itr_to = std::find(itr_from + 1, line.end(), del);
    }
}

点击这里查看实时示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接