string removeNonAlphas(string original)
{
for(int i = 0; i < original.size(); ++i){
if(!(original[i] > 64 && original[i] < 91) &&
!(original[i] > 96 && original[i] < 124)){
original[i] = original[i] - original[i];
}
}
return original;
}
// test1.cpp
string test = "abc abc";
cout << removeNonAlphas(test) << endl; // output = "abcabc"
assert(removeNonAlphas(test) == "abcabc"); // assertion failed
//为什么断言失败? removeNonAlphas结果(&#34; abcabc&#34;)与 // rhs&#34; abcabc&#34;
答案 0 :(得分:3)
original[i] = original[i] - original[i];
这使得它使用'\0'
重新定位角色,但不删除它。因此,输出不是"abcabc"
而是"abc\0abc"
。 '\0'
不可打印,因此您不会在输出中看到它,但在将其与==
进行比较时会显示。
不是替换字符串中的字符,而是在迭代旧字符串时创建一个新字符串:
string removeNonAlphas(string const& original)
{
std::string result;
for(char c : original)
if((c > 64 && c < 91) ||
(c > 96 && c < 124))
result.push_back(c);
return result;
}
注意:更喜欢使用std::isalpha
而不是硬编码值。
答案 1 :(得分:1)
两个值都不相同,但区别在于非打印字符,因此您无法看到与cout
和肉眼有任何差异。
尝试使用适当的工具(如调试器),您将看到函数结果中存在额外的\0
字符。
答案 2 :(得分:1)
您实际上并没有删除字符串中的任何字符。你只是给它们赋值0.它只是看起来有效 - 这是最糟糕的。 '\0'
只是一个不可打印的字符,这就是为什么它看起来像是打印相同的。 ==
实际上会检查每个角色,即使是不可打印的角色,所以它会捕捉到你看不到的东西。
值得庆幸的是,string
类通过提供这样的成员函数,使erase
字符变得容易:
original.erase(i, 1); // erase a single character starting at i
现在仅凭这还不够。你删除一个字符,现在i
“指向”下一个元素 - 但你不会检查它。如果我们有"abc12abc"
,则在删除1
后,我们会跳过2
。所以我们需要改变迭代的方式:
for (std::string::iterator it = original.begin();
it != original.end();
/* nothing */)
{
// here's a better way to do checking
if (!(*it >= 'A' && *it <= 'Z') &&
!(*it >= 'a' && *it <= 'z'))
{
// erase(iterator ) will return the next iterator
it = original.erase(it);
}
else
{
++it;
}
}
那会有用。它也非常冗长。而且容易出错。这就是为什么我们有擦除 - 删除习语:
original.erase(
std::remove_if(original.begin(),
original.end(),
[](char c) { return !std::isalpha(c); }),
original.end()
);
return original;