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

时间:2022-09-13 13:18:07

I want to delete all characters between two same characters in a string. My function takes a string (by reference) and a char in its arguments.

我想删除字符串中两个相同字符之间的所有字符。我的函数在其参数中使用一个字符串(通过引用)和一个char。

Assuming that I used an std::string variable like this: "hah haaah hah hello!" as the first parameter and a char 'h' as the second parameter, something like this should happen: "hah haaah hah hello!" ===> "hh hh hh hello". As you can see, every character between two h characters has been removed. How do I achive something like this?

假设我使用了这样的std :: string变量:“hah haaah hah hello!”作为第一个参数和char'h'作为第二个参数,这样的事情应该发生:“hah haaah hah hello!” ===>“嗯......你好”。如您所见,两个h字符之间的每个字符都已被删除。我怎么做这样的事情?

I've tried to use iterators and ended up with this:

我试过使用迭代器并最终得到这个:

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

First, I search for the first occurrence of del, I store the iterator to its position in itr_from. After that, I search for the second occurrence of del. And finally I run a while loop that starts by erasing characters in a certain range if itr_to is valid. I repeat that over and over again while my iterators are not equal to line.end().

首先,我搜索del的第一次出现,我将迭代器存储到itr_from中的位置。之后,我搜索del的第二次出现。最后,如果itr_to有效,我会运行一个while循环,首先擦除某个范围内的字符。我一遍又一遍地重复这一点,而我的迭代器不等于line.end()。

But for some reason, this code doesn't work properly. It sometimes removes whitespaces and doesn't even touch the characters I was aiming to delete.

但由于某些原因,此代码无法正常工作。它有时会删除空格,甚至不会触及我想要删除的字符。

Thanks for your help.

谢谢你的帮助。

2 个解决方案

#1


3  

std::string iterators are invalidated by all operations which modify the length of the string, so using itr_from and itr_to after the call to line.erase is Undefined Behaviour.

所有修改字符串长度的操作都会使std :: string迭代器失效,因此在调用line.erase之后使用itr_from和itr_to是Undefined Behavior。

You need to use the return value of erase:

你需要使用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;
}

#2


0  

To avoid undefined behavior you should reset both iterators before calling erase.

为避免未定义的行为,您应在调用erase之前重置两个迭代器。

Looking at the expected output it seems that a closing delimiter shouldn't be used to start another interval:

查看预期的输出似乎不应该使用结束分隔符来启动另一个间隔:

"hh hh hh hello"  not  "hhhhhhhello"
   ^  ^  ^

So, this is my proposal:

所以,这是我的建议:

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);
    }
}

Live example HERE.

这里有实例。

#1


3  

std::string iterators are invalidated by all operations which modify the length of the string, so using itr_from and itr_to after the call to line.erase is Undefined Behaviour.

所有修改字符串长度的操作都会使std :: string迭代器失效,因此在调用line.erase之后使用itr_from和itr_to是Undefined Behavior。

You need to use the return value of erase:

你需要使用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;
}

#2


0  

To avoid undefined behavior you should reset both iterators before calling erase.

为避免未定义的行为,您应在调用erase之前重置两个迭代器。

Looking at the expected output it seems that a closing delimiter shouldn't be used to start another interval:

查看预期的输出似乎不应该使用结束分隔符来启动另一个间隔:

"hh hh hh hello"  not  "hhhhhhhello"
   ^  ^  ^

So, this is my proposal:

所以,这是我的建议:

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);
    }
}

Live example HERE.

这里有实例。