为什么没有访问所有字符串字符?

Why aren't all the string characters being accessed?

本文关键字:字符 字符串 访问 为什么      更新时间:2023-10-16

我的程序的目的是删除字符串中的所有元音。

std::string disemvowel(std::string str)
{
for (unsigned int i = 0; i < str.length(); ++i)
{
switch(str[i])
{
case 'A':
case 'a':
case 'E':
case 'e':
case 'I':
case 'i':
case 'O':
case 'o':
case 'u':
case 'U': str.erase(str.begin() + i);
break;
default: 
break;
}
}
return str;
}

输入字符串:aaAAaiieEeOoU,,,.,132@

访问和删除的字符为:aAaiEOU,,.,132@

结果字符串:aAieeo,,,.,132@

该程序似乎永远不会访问上面的元音。

我认为我如何处理这个问题没有任何问题。我应该访问字符串中的每个字符,直到其长度结束,不是吗?

每次擦除字符时,str都会更改,然后当您递增i时,您将跳过下一个字母。

通常,不要在迭代序列时从序列中删除内容,但是如果您使用索引进行迭代,那么如果可以的话,一个好的技巧是向后移动。你i之后改变了一切,但你不在乎。

试试这个 -

std::string disemvowel(std::string str)
{
for (unsigned int i = 0; i < str.length(); ++i)
{
switch(str[i])
{
case 'A':
case 'a':
case 'E':
case 'e':
case 'I':
case 'i':
case 'O':
case 'o':
case 'u':
case 'U': str.erase(str.begin() + i),i--;
break;
default: 
break;
}
}
return str;
}

您正在删除一个字符并移动到下一个字符。但是,当您删除当前字符时,您将下一个字符移动到当前索引。所以你的循环跳过了几个字母。上面的代码将起作用。


另一种可能的解决方案是向后循环,这样您不必担心删除元音后索引的增加/减少。

另一种简单的方法,只是为了让你知道它的存在,是使用正则表达式的解决方案,如下所示 -

std::string disemvowel(std::string str)
{
regex r("[aAeEiIoOuU]");  
return regex_replace(str, r, ""); 
}

您必须使用#include <regex>才能使用上述解决方案。

希望这有帮助!

你可以用std::remove_if和函数来实现这一点:

auto is_vowel(char c) -> bool {
switch(c) {
case 'A':
case 'a':
case 'E':
case 'e':
case 'I':
case 'i':
case 'O':
case 'o':
case 'u':
case 'U':
return true;
default: 
return false;
}
}
auto disemvowel(std::string str) -> std::string {
str.erase(
std::remove_if(str.begin(), str.end(), is_vowel),
str.end()
);
return str;
}

调用std::remove_ifstd::string::erase实现算法,以根据条件正确有效地删除多个字符。

如果您不使用此类提供的算法,则必须考虑已删除内容的索引,方法是反向迭代或在从字符串中删除字符时不增加索引。

我建议采用两次通过的方法。

  1. 在第一遍中,您构建要删除的所有元素的容器(向量(。
  2. 在第二遍中,您将构建一个新string,仅包含未删除的元素。

当您从除向量、字符串或数组末尾以外的任何位置删除元素时,您必须将 1 之后的所有值复制到其原始位置的正前方。 O(n^2(. 上面的方法只是 O(n(。 遍历字符串和向量对缓存非常友好,所以这不是一个问题。

请注意,防止传递 2 变为 O(n^2( 会使代码稍微复杂一些,但完全可行。