【问题标题】:C++ erase vowels in list<string>C ++擦除列表中的元音<字符串>
【发布时间】:2014-03-13 22:23:24
【问题描述】:

我有一个大学作业要编写一个函数,该函数必须在字符串列表中删除所有检测到的元音,然后,列表需要从最大到最小的字符串排序。

我尝试过类似于int 的列表来定义迭代器,取消引用它并与if 的字符进行比较,并对所有元音执行此操作,但这是行不通的。

我需要在下面的代码中进行哪些更改?我首先尝试写main() 来测试它是否可以编译。提前致谢。

int main()
{
    string x;
    list<string> vowel;

    while (cin >> x)
        vowel.push_back(x);

    list<string>::iterator k;

    for(auto k=vowel.begin(); k!=vowel.end(); k++)
        if(*k == 'A' || *k =='a' || ...) // for every letter that is a vowel
            vowel.erase(*k);

    vowel.sort();

    return 0;
}

【问题讨论】:

  • 您遇到了什么具体问题?
  • 您的意思是从 字符 列表中删除所有元音(这是一个字符串)还是在字符串列表中查找并删除所有元音?你能举一个预期行为的例子吗? (因为我认为您的意思是第一个。)
  • 大学作业?这是作业吗?

标签: c++ string list c++11


【解决方案1】:

要检查字符是否为元音,您可以在所有元音的std::vectorstd::find 它:

static inline bool isVowel( char ch)
{
        static const std::string vowels("aeiouEAIOU");
        return vowels.end() != std::find(vowels.begin(), vowels.end(), ch);
}

用法:

std::assert( isVowel( 'a') == true);

例子:

int main()
{
    std::string x;
    std::vector< std::string> vowel;
    vowel.push_back( "a");
    vowel.push_back( "b");
    vowel.push_back( "c");
    vowel.push_back( "d");
    vowel.push_back( "e");
    vowel.push_back( "f");

    std::vector< std::string>::iterator k;

    for( k = vowel.begin(); k != vowel.end();)
      if( isVowel( *((*k).c_str())))
          k = vowel.erase(k);
      else
          ++k;

    return 0;
}

将 std::remove_if 与仿函数一起使用

这通常比使用函数更快。应用运算符可以轻松内联。

struct isVowel_{
    std::string& vowels;
    isVowel_( std::string& s) : vowels( s) {}
    bool operator()( std::string c) const {
        return vowels.end() != std::find(vowels.begin(), 
                                                  vowels.end(), *(c.c_str()));
    }
};

int main()  {
  std::vector<std::string> vowel;
  vowel.push_back("a");
  vowel.push_back("b");
  vowel.push_back("c");
  vowel.push_back("d");
  vowel.push_back("e");
  vowel.push_back("f");

  std::vector<std::string>::iterator k;
  std::string vowels("aeiouEAIOU");

  k = std::remove_if( vowel.begin(), vowel.end(), isVowel_( vowels));

  vowel.erase( k, vowel.end());  // erases the unspecified values and reduces
                                 // the physical size of the container to match
                                 // its new logical size
  return 0;
}

【讨论】:

  • 很好,但使用谓词会更好:) +1,无论如何。
  • true,已添加。谢谢!
【解决方案2】:

您的代码有一些问题可能需要解决:

1。命名

名称vowel 不是输入字符串列表的好名称。像

std::list<std::string> inputStringList

会更好。

2。迭代器声明

您将变量k 声明了两次。来到这里:

list<string>::iterator k;

又在这里:

for(auto k=vowel.begin(); k!=vowel.end(); k++)

您应该只声​​明一次变量。去掉第一个声明。

3。字符串比较

在这段代码中:

for(auto k=vowel.begin(); k!=vowel.end(); k++)
    if(*k == 'A' || *k =='a' || ...) // for every letter that is a vowel
        vowel.erase(*k);

您将k 的值(即std::string)与“A”(即char)进行比较。不要这样做。您应该将字符串与字符串或字符与字符进行比较,但不要混用和匹配。要么将您的 vowel 声明更改为 std::list&lt;char&gt;,要么更改您的 if 语句以比较字符串

if (*k == "A" || ...)
    //    ^-^--- Note use of double-quotes for a string literal.

4。未定义的行为

当您从列表中删除每个字符串时,您正在参与undefined behaviour

vowel.erase(*k);

一旦你从列表中删除了字符串,你的迭代器就失效了,但是你继续在for循环的下一次迭代中再次使用它(k++)。你可能侥幸逃脱,但我希望不会。

请记住,即使它确实有效(但它没有),您最终还是会跳过您没有检查过的字符,因为擦除字符串之后的字符串都会上移一位。

最好使用while 循环来迭代和擦除。像这样:

auto iter = myList.begin();
const auto endIter = myList.end();

while (iter != endIter)
{
    if (some test here)
      myList.erase(iter++);
    else
      ++iter;
}

为什么可以找到这个工作原理here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-18
    • 2018-11-23
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-22
    • 2022-08-13
    • 1970-01-01
    相关资源
    最近更新 更多