删除 std::vector<std::string> 中与另一个给定 std::string 中的字符匹配的元素

Delete elements in a std::vector<std::string> which matches with the characters in another given std::string

如何删除向量 alphabets 中与字符串 plaintext 中的任何字符匹配的元素?

这是我的尝试:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

int main()
{
   //init
   std::vector<std::string> alphabets{ "a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
   //input
   std::string plaintext;
   std::cout << "enter plain text: ";
   std::cin >> plaintext;

   for (std::string::iterator it = plaintext.begin(); it != plaintext.end(); it++)
   {
      std::vector<std::string>::iterator toErase;
      toErase = std::find(alphabets.begin(), alphabets.end(), *it);
      if (toErase != alphabets.end())
      {
         alphabets.erase(toErase);
      }
   }
}

当我试图编译它时。但是我得到了这个错误:

17: note:   'std::__cxx11::basic_string<char>' is not derived from
'const std::istreambuf_iterator<_CharT, _Traits>' { return *__it == _M_value; }
...

203 : 5 : note : candidate : 'template<class _CharT, class _Traits> bool 
std::operator==(const std::istreambuf_iterator<_CharT, _Traits>&, const
   std::istreambuf_iterator<_CharT, _Traits>&)'
   operator==(const istreambuf_iterator<_CharT, _Traits> & __a,
      ...

*it 的类型是 char 而不是 std::string。这就是编译器所抱怨的。因此,您需要按如下方式将 std::string 传递给 std::find

auto toErase = std::find(alphabets.begin(), alphabets.end(), std::string{ *it });
 //                                                          ^^^^^^^^^^^^^^^^^^

这里是a demo.


此外,请注意以下事项:

  • 您可以将 std::vector<std::string> alphabets 更改为 std::vector<char> alphabets 甚至一个 std::string 作为你的 alphabets containes/ 将 chars 表示为字符串。在 std::string 的情况下(即 alphabets),std::basic_string::find 更适合使用,而不是首先使用更通用的std::find
  • 对于矢量擦除,你可以使用erase–remove 成语,或 从 C++20 开始,使用 std::vector 本身的 non-member 函数,所以 称为 std::erase_if.

我是这样理解的:
你有一个字符串说 str1。现在你得到了另一个字符串 str2。现在您要删除 str1 中存在于 str2.

中的所有字符

在这种情况下,我建议将输入扫描为字符串而不是向量,然后使用 delete 循环

for(auto it = str1.begin(); it != str1.end(); it++) {
    if(str2.find(std::string{*it}) != std::string::npos) {
        it = str1.erase(it);
    }
}

std::find(alphabets.begin(), alphabets.end(), *it);

alphabets.begin()alphabets.end()std::string 迭代器的 std::vector,但是 itstd::string 迭代器,它迭代字符,这些参数不兼容,如果不进行某种转换,则不能在 std::find 中一起使用。

也就是说,更正代码的更好方法是将过于复杂的 alphabets 容器从 std::vector<std::string> 转换为简单的 std::string.

Live demo

//init
std::string alphabets{"abcdefghiklmnopqrstuvwxyz"}; //<--- simple string

//input
std::string plaintext;
std::cout << "enter plain text: ";
std::cin >> plaintext;

for (std::string::iterator it = plaintext.begin(); it != plaintext.end(); it++)
{
    std::string::iterator toErase; //<--- string iterator
    /*or auto */ toErase = std::find(alphabets.begin(), alphabets.end(), *it);
    if (toErase != alphabets.end())
    {
        alphabets.erase(toErase);
    }
}

C++20 oneliner 解决方案。

它更关注你想做什么(它使用std::erase_if because we want to erase elements based on a condition, and it uses std::find来检查那个条件),而不是如何 你这样做(确实没有 for 循环。

#include <string>
#include <vector>
#include <iostream>

int main() {

    // inputs
    // I don't like this alphabet; a std::vector<char> would have been much better
    // and it would allow to remove the ugly [0] in the std::find below
    std::vector<std::string> alphabet{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
    std::string plaintext{"abcdefghijklmnopq"};


    // the solution is a oneliner
    std::erase_if(alphabet, [&plaintext](auto x){
        return !(std::find(std::begin(plaintext), std::end(plaintext), x[0]) == std::end(plaintext));
    });

    // output to verify the correct result
    for (auto& e : alphabet) { // prints r s t u v w x y z
        std::cout << e << ' ';
    }
}