【问题标题】:std::string::erase() erases everything after 1st char found with std::string::find()std::string::erase() 擦除用 std::string::find() 找到的第一个字符后的所有内容
【发布时间】:2015-05-27 11:55:04
【问题描述】:

我仍然很难说出这个问题的标题,看看这段代码:

#include <iostream>
#include <string>
#include <algorithm>

int main(){
    std::string s1 = " Hello World  1 ";
    std::string s2 = " Hello World  2 ";
    while(s1.find(' ') != std::string::npos){
        s1.erase(s1.find(' '));
    }
    while(s2.find(' ') != std::string::npos){
        s2.erase(std::find(s2.begin() , s2.end() ,' '));
    }
    std::cout<<s1<<"\n";
    std::cout<<s2;
    return 0;
}

我正在使用std::string::find() 来检测字符串中是否存在空格,如果仍然存在,请使用std::string::erase() 删除它们。

我尝试了两种不同的方法:

s1.erase(s1.find(' '));

s2.erase(std::find(s2.begin() , s2.end() ,' '));

但是,在第一种方法中,它会在字符串中找到第一次出现的' ' 空格并将其删除以及其后的所有内容。第二种方法按预期工作。

当前输出为:

HelloWorld2

谁能告诉我第一次发生后删除所有内容的第一种方法背后的原因是什么?快速浏览:link

相关链接:

std::basic_string::find

std::find

std::basic_string::erase

【问题讨论】:

  • 标准stl删除方法应该是s1.erase(std::remove(s1.begin(), s1.begin(), value), s1.end())
  • “前面”是指从空格的位置到字符串的末尾吗?
  • std::string::erase() 接受索引和迭代器作为参数。
  • @beaker 我已将输出添加到 answer ,是的。如果第一个字符是空格,它将删除整个字符串。
  • @RemyLebeau 我不明白。你能解释一下吗?可能写一个答案。

标签: c++ string c++11


【解决方案1】:

我正在使用std::string::find() 来检测字符串中是否存在空白,如果仍然存在,请使用std::string::erase() 将其删除。

您不需要在每次循环迭代中调用 find() 两次。调用一次并将返回值保存到一个变量中,然后检查该变量的值并将其传递给erase()(如果需要)。

我尝试了两种不同的方法

s1.erase(s1.find(' '));

s2.erase(std::find(s2.begin() , s2.end() ,' '));

然而,在第一种方法中,它会在字符串中找到第一次出现的 ' ' 空白并将其删除以及它后面的所有内容。

阅读您链接到的documentation。您正在调用将索引作为其第一个参数的erase() 版本:

basic_string& erase( size_type index = 0, size_type count = npos );

当您没有指定 count 值时,它会设置为 npos,这会告诉 erase() 从指定的 index 开始从 string 中删除 everything字符串的结尾。您的 string 以空格字符开头,因此您正在清除 整个字符串,这就是它没有出现在输出中的原因。

您需要将 count 指定为 1 以仅删除 find() 找到的空格字符:

do
{
    std::string size_type pos = s1.find(' ');
    if (pos == std::string::npos)
        break;
    s1.erase(pos, 1); //  <-- erase only one character
}
while (true);

或者,您应该使用find() 的第二个参数,这样您就可以在上一次迭代停止的地方开始下一次循环迭代。没有它,你每次都会回到字符串的开头并重新搜索你已经搜索过的字符:

std::string::size_type pos = 0;
do
{
    pos = s1.find(' ', pos); // <-- begin search at current position
    if (pos == std::string::npos)
        break;
    s1.erase(pos, 1); // <-- erase only one character
}
while (true);

或者,如果您愿意:

std::string::size_type pos = s1.find(' ');
while (pos != std::string::npos)
{
    s1.erase(pos, 1); // <-- erase only one character
    pos = s1.find(' ', pos); // <-- begin search at current position
}

第二种方法按预期工作。

您正在调用不同版本的erase()

iterator erase( iterator position );

std::find() 返回一个iterator。此版本的erase() 仅删除迭代器指向的单个字符。

【讨论】:

  • 谢谢 :) ,我们也可以使用相同的 while 循环 std::string s1 = "Hello World 1 "; std::string::size_type p = s1.find(' '); while(p!= std::string::npos){ s1.erase(p , 1); p = s1.find(' '); } 添加它
  • @AbhinavGauniyal:您仍然要回到字符串的开头并在每次循环迭代时重新搜索 entire 字符串,这对于您已经跳过的字符来说是多余的.最好通过使用find() 的第二个参数来避免这种开销,方法是将循环底部的p = s1.find(' ') 更改为p = s1.find(' ', p)。我已将该示例添加到我的答案中。
  • 感谢这些有用的编辑,我现在明白了 :) std::basic_string::find 也有过载。
【解决方案2】:

谁能告诉我第一种方法删除的原因是什么 第一次发生之前的一切?

std::basic_string::find 返回找到的子字符串的第一个字符的位置 (size_type) 或 std::string::npos

因此,s1.erase(s1.find(' ')); 将简单地从位置 0 擦除到字符串的 end。注意第一个循环只执行一次!

【讨论】:

    【解决方案3】:

    你的电话

    s1.find(' ')
    

    返回第一个空格的位置,在您的情况下为0。然后你打电话给

    s1.erase(s1.find(' ')); // i.e. s1.erase(0);
    

    它从位置0 擦除到字符串的末尾,因为它调用了重载

    basic_string& erase( size_type index = 0, size_type count = npos );
    

    号码 1 from here。 如果你传递1 而不是默认的npos

    s1.erase(s1.find(' '), 1); // pass 1 instead of default npos
    

    然后它按预期工作。

    【讨论】:

    • 我从未见过默认参数:(。谢谢+1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-26
    • 1970-01-01
    • 2014-01-25
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    相关资源
    最近更新 更多