使用字符串擦除()和字符串长度()从字符串中删除某些字符

Posted

技术标签:

【中文标题】使用字符串擦除()和字符串长度()从字符串中删除某些字符【英文标题】:Using string erase() and string length() to delete certain chars from a string 【发布时间】:2018-03-29 14:14:31 【问题描述】:

我在下面编写了一个函数来遍历字符串并删除所有空格' ''-'s。但是,它跳过了字符串的一些元素并在末尾留下了'-',因此逻辑一定是不正确的。谁能发现我哪里出错了?

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

string FormatString(string S)  

    size_t original_size = S.length();

    cout << "Length at start is " << S.length() << "\n";

    /*Count spaces and dashes*/
    for(size_t i = 0; i < S.length(); i++) 

        cout << "Current letter is " << S[i] << "\n";

        if((S[i] == ' ') || (S[i] == '-')) 
            cout << "Deleting current letter " << S[i] << "\n";
            S.erase (i,1);
            cout << "Length is now " << S.length() << "\n";

        
    

    std::cout << S << '\n';

    return S;



int main() 

    std::string testString("AA BB-4499--5");
    std::string result = FormatString(testString);
    cout << result << endl; // prints !!!Hello World!!!
    return 0;

输出是:

Length at start is 13
Current letter is A
Current letter is A
Current letter is  
Deleting current letter  
Length is now 12
Current letter is B
Current letter is -
Deleting current letter -
Length is now 11
Current letter is 4
Current letter is 9
Current letter is 9
Current letter is -
Deleting current letter -
Length is now 10
Current letter is 5
AABB4499-5
AABB4499-5

【问题讨论】:

erase-remove idiom 我猜不可能使用std::remove_if 【参考方案1】:

这是因为您在擦除后增加了位置。

当您进行擦除时,会将所有其他字符向下移动一个。如果你还增加你在字符串中的位置,你实际上跳过了一个字符。

如果我们从这个开始:

"AA BB-4499--5"

删除几个字符后,我们剩下这个

"AABB4499--5"
         ^           // i is 9.

您现在删除光标上方的字符。

"AABB4499-5"
         ^           // i is 9.

现在开始循环的下一次迭代。

"AABB4499-5"
          ^          // i is 10.

你注意到你跳过了一个字符。

这个算法的一个更好的实现是:

for(size_t i = 0; i < S.length();)      // Notice no increment here
    if((S[i] == ' ') || (S[i] == '-')) 
        S.erase (i,1);
    
    else 
        ++i;
    

我们可以使用迭代器对此进行改进:

for(auto loop = std::begin(S); loop != std::end(S);) 
    if (*loop == ' ' || *loop == '-') 
        loop = S.erase(loop);
    
    else 
        ++loop;
    

现在我们正在使用迭代器,我们可以循环使用标准算法

auto newEnd = std::remove_if(std::begin(S), std::end(S),
                             [](char c)return c == ' ' || c == '-';);
std::erase(newEnd, std::end(S));

【讨论】:

此语法是否适用于特定版本的 C++ 或仅用于说明目的?我已经把它改成了这个谢谢auto newEnd = remove_if(S.begin(), S.end(), [](char c)return c == ' ' || c == '-';); S.erase(newEnd, S.end()); @samsunggather 这是 C++11 语法。我更喜欢std::begin(s) 而不是s.begin(),因为您可以更轻松地概括这些类型。 std::begin(s) 将适用于所有标准容器,但也适用于 C 阵列。【参考方案2】:

这个函数的问题是,当一个字符被擦除时,索引却增加了。所以一些相邻的字符仍然会在字符串中。

最好使用基于标准算法std::removestd::remove_if的所谓习语erase-remove。

这是一个演示程序

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

std::string FormatString( const std::string &s, const std::string &erased = " -" )

    const char *data = erased.data();

    std::string t( s );

    t.erase( std::remove_if( t.begin(), t.end(), [=]( char c )  return std::strchr( data, c );  ), 
             t.end() );

    return t;


int main() 

    std::string testString( "AA BB-4499--5" );

    std::cout << FormatString( testString ) << std::endl;

    return 0;

它的输出是

AABB44995

【讨论】:

以上是关于使用字符串擦除()和字符串长度()从字符串中删除某些字符的主要内容,如果未能解决你的问题,请参考以下文章

pandas 替换(擦除)字符串中的不同字符

使用擦除从“(”到“)”中删除 std::string 中的字符?

stl中字符串中的擦除关键字的工作?

使用指针从 char array[] 中删除/删除字符

Shell脚本中计算字符串长度的5种方法及从文本获取某一行

C++中erase函数的使用,可以用来删除内存擦除