使用字符串擦除()和字符串长度()从字符串中删除某些字符
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::remove
或std::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
【讨论】:
以上是关于使用字符串擦除()和字符串长度()从字符串中删除某些字符的主要内容,如果未能解决你的问题,请参考以下文章