【问题标题】:How to remove all the occurrences of a char in c++ string如何删除C++字符串中所有出现的字符
【发布时间】:2013-12-18 01:07:03
【问题描述】:

我正在使用以下内容:

replace (str1.begin(), str1.end(), 'a' , '')

但这会导致编译错误。

【问题讨论】:

  • '' 确实不是字符。
  • 嗯,知道你遇到的错误肯定会有所帮助。
  • 很好,在很多情况下替换是一个合适的想法,而不是这个。

标签: c++ stl


【解决方案1】:

使用copy_if

#include <string>
#include <iostream>
#include <algorithm>
int main() {
    std::string s1 = "a1a2b3c4a5";
    std::string s2;
    std::copy_if(s1.begin(), s1.end(), std::back_inserter(s2),
         [](char c){ 
                std::string exclude = "a";
                return exclude.find(c) == std::string::npos;}
    );

    std::cout << s2 << '\n';
    return 0;
}

【讨论】:

  • -1 如果s1 比固定大小的字符串s2 长,此代码会导致缓冲区溢出。此外,s2 没有正确终止,因为s1 末尾的 NUL 字节没有被复制。最后,发帖者要求就地解决方案,而不是生成新字符串。
  • 你是对的,但似乎 NULL 字节错误是由@jimifiki 引入的。对于固定长度,示例工作得很好,但我同意可以更通用。
  • 我为我的错误编辑道歉。随意使用此行 s1.erase(std::copy_if(s1.begin(), s1.end(), s1.begin(), [](char c){return c!='a';}) );寻求安全的就地解决方案
  • @KaiPetzke 我编辑了答案以减轻您的担忧。
  • 是的,现在看起来很干净。
【解决方案2】:

算法std::replace 在给定序列上按元素 工作(因此它用不同的元素替换元素,并且不能用nothing 替换它)。但是没有 empty 字符。如果你想从一个序列中移除元素,下面的元素必须被移动,而std::replace不是这样工作的。

您可以尝试将std::remove()str.erase()1 一起使用来实现此目的。

str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());

【讨论】:

    【解决方案3】:

    从 C++20 开始,std::erase() 已添加到标准库中,它将对 str.erase()std::remove() 的调用合并为一个函数:

    std::erase(str, 'a');
    

    作用于字符串的std::erase() 函数重载直接在&lt;string&gt; 头文件中定义,因此不需要单独的包含。为所有其他容器定义了类似的重载。

    【讨论】:

      【解决方案4】:

      我正在读取一个字符串:

      "\"internet\""
      

      我想删除引号。我使用了上面建议的std::erase 解决方案:

      str.erase(std::remove(str.begin(), str.end(), '\"'), str.end());
      

      但是当我对结果进行比较时它失败了:

      if (str == "internet") {}
      

      我实际上得到的是:

      "internet "
      

      std::erase / std::remove 解决方案在删除结尾时不会缩短字符串。我添加了这个(来自https://stackoverflow.com/a/21815483/264822):

      str.erase(std::find_if(str.rbegin(), str.rend(), std::bind1st(std::not_equal_to<char>(), ' ')).base(), str.end());
      

      删除尾随空格。

      【讨论】:

      • 您确定您读入的字符串是"\"internet\"" 而不是"\"internet\" "
      【解决方案5】:

      比最佳答案快 70% 的解决方案

              void removeCharsFromString(std::string& str, const char* charsToRemove)
              {
                  size_t charsToRemoveLen = strlen(charsToRemove);
                  std::remove_if(str.begin(), str.end(), [charsToRemove, charsToRemoveLen](char ch) -> bool
                      {
                          for (int i = 0; i < charsToRemoveLen; ++i) {
                              if (ch == charsToRemove[i])
                                  return true;
                          }
                          return false;
                      });
              }
      

      【讨论】:

      • 此代码未能设置新字符串的结尾。
      【解决方案6】:

      此代码删除重复字符,即,如果输入是 aaabbcc,则输出将为 abc。 (此代码必须对数组进行排序才能正常工作)

      cin >> s;
      ans = "";
      ans += s[0];
      for(int i = 1;i < s.length();++i)
      if(s[i] != s[i-1])
          ans += s[i];
      cout << ans << endl;
      

      【讨论】:

        【解决方案7】:

        根据其他答案,这里还有一个示例,我删除了给定字符串中的所有特殊字符:

        #include <iostream>
        #include <string>
        #include <algorithm>
        
        std::string chars(".,?!.:;_,!'\"-");
        
        int main(int argc, char const *argv){
        
          std::string input("oi?");
          std::string output = eraseSpecialChars(input);   
        
         return 0;
        }
        
        
        
        
        std::string eraseSpecialChars(std::string str){
        
        std::string newStr;
            newStr.assign(str);  
        
            for(int i = 0; i < str.length(); i++){
                for(int  j = 0; j < chars.length(); j++ ){
                    if(str.at(i) == chars.at(j)){
                        char c = str.at(i);
                        newStr.erase(std::remove(newStr.begin(), newStr.end(), c), newStr.end());
                    }
                }
        
            }      
        
        return newStr; 
        }
        

        输入与输出:

        Input:ra,..pha
        Output:rapha
        
        Input:ovo,
        Output:ovo
        
        Input:a.vo
        Output:avo
        
        Input:oi?
        Output:oi
        

        【讨论】:

          【解决方案8】:

          如果您有 predicate 和/或非空 output 来填充过滤后的字符串,我会考虑:

          output.reserve(str.size() + output.size());  
          std::copy_if(str.cbegin(), 
                       str.cend(), 
                       std::back_inserter(output), 
                       predicate});
          

          在原始问题中,谓词是[](char c){return c != 'a';}

          【讨论】:

            【解决方案9】:
            string RemoveChar(string str, char c) 
            {
               string result;
               for (size_t i = 0; i < str.size(); i++) 
               {
                      char currentChar = str[i];
                      if (currentChar != c)
                          result += currentChar;
               }
                   return result;
            }
            

            我就是这样做的。

            或者你可以像安托万所说的那样做:

            this question 这回答了同样的问题。在你的情况下:

            #include <algorithm>
            str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
            

            【讨论】:

              【解决方案10】:

              基本上,replace 将一个字符替换为另一个字符,'' 不是一个字符。你要找的是erase

              参见this question,它回答了同样的问题。在你的情况下:

              #include <algorithm>
              str.erase(std::remove(str.begin(), str.end(), 'a'), str.end());
              

              如果您愿意,也可以使用boost,例如:

              #include <boost/algorithm/string.hpp>
              boost::erase_all(str, "a");
              

              所有这些都在referencewebsites 上有详细记录。但是如果你不知道这些功能,你可以很容易地用手做这种事情:

              std::string output;
              output.reserve(str.size()); // optional, avoids buffer reallocations in the loop
              for(size_t i = 0; i < str.size(); ++i)
                if(str[i] != 'a') output += str[i];
              

              【讨论】:

              • 你提供的算法不是O(n^2)吗?
              • @jww:我假设您说的是最后一个代码示例,n 是原始字符串长度。对于每个输入字符,我进行 1 个字符测试 O(1),并附加 0 或 1 个字符。字符追加为O(1) 是否保留了足够的内存,或者O(current_length) 如果分配了新缓冲区。如果你在循环之前执行output.reserve(str.size()),这永远不会发生,并且你有一个全局O(n) 成本。否则渐近,我猜成本是O(n . log(n) ),因为 STL 容器重新分配策略。
              • 我需要#include
              • @DmitryNichiporenko for 的答案不可能是最合适的。如果您有谓词或非空输出,我宁愿考虑: output.reserve(str.size()+output.size()); std::copy_if(str.begin(), str.end(), std::back_inserter(输出), [](char c){return predicate(c);});
              • @ViktorStefanov C++ 的级别比 python 低,这意味着你对事物有更多的控制权,但它通常更冗长,而且魔鬼在细节中。标准库(在我看来)设计不佳的事实无济于事。在这种情况下,remove 不能改变字符串的长度,所以它只是随机播放字符。然后你必须调用earse 来基本上改变字符串的长度。 See wiki
              【解决方案11】:

              这就是我的做法:

              std::string removeAll(std::string str, char c) {
                  size_t offset = 0;
                  size_t size = str.size();
              
                  size_t i = 0;
                  while (i < size - offset) {
                      if (str[i + offset] == c) {
                          offset++;
                      }
              
                      if (offset != 0) {
                          str[i] = str[i + offset];
                      }
              
                      i++;
                  }
              
                  str.resize(size - offset);
                  return str;
              }
              

              基本上每当我找到给定的字符时,我都会提前偏移并将字符重新定位到正确的索引。我不知道这是否正确或有效,我正在(再次)开始使用 C++,我将不胜感激。

              【讨论】:

              • 4个月后回头看这个问题,我真的不知道为什么我没有使用std::erase或std::replace。
              【解决方案12】:

              我猜 std:remove 方法有效,但它给包含的一些兼容性问题,所以我最终写了这个小函数:

              string removeCharsFromString(const string str, char* charsToRemove )
              {
                  char c[str.length()+1]; // + terminating char
                  const char *p = str.c_str();
                  unsigned int z=0, size = str.length();
                  unsigned int x;
                  bool rem=false;
              
                  for(x=0; x<size; x++)
                  {
                      rem = false;
                      for (unsigned int i = 0; charsToRemove[i] != 0; i++)
                      {
                          if (charsToRemove[i] == p[x])
                          {
                              rem = true;
                              break;
                          }
                      }
                      if (rem == false) c[z++] = p[x];
                  }
              
                  c[z] = '\0';
                  return string(c);
              }
              

              只要用作

              myString = removeCharsFromString(myString, "abc\r");

              它会删除所有出现的给定字符列表。

              这也可能更高效一些,因为循环在第一次匹配后返回,所以我们实际上做的比较少。

              【讨论】:

              • 你猜对了。与其自己编写,不如找出为什么不能使用标准 C++ 头文件。
              • 嗯,这是个人意见 xtofl,使用 3rd 代码并不总是好的,你实际上不知道它做了什么,也不知道它的性能,而不是写你特别需要的东西。
              • 我明白你的意思。谦虚让我选择了经过专业全职图书馆作家而不是我自己的审查、测试和优化的版本。 标准库可以被认为是必需的知识:它的功能以及它的运行时复杂性。
              • 抛开字符串,这是一个 C++ 问题的 C 解决方案。我认为这不应该被否决。
              【解决方案13】:
              #include <string>
              #include <algorithm>
              std::string str = "YourString";
              char chars[] = {'Y', 'S'};
              str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
              

              将从 str 中删除大写的 Y 和 S,留下“ourtring”。

              请注意,remove 是一种算法,需要包含标头 &lt;algorithm&gt;

              【讨论】:

              • 是的,我认为他遗漏的 hte 数组字符存在一个隐含循环
              猜你喜欢
              • 1970-01-01
              • 2020-08-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-08-07
              • 1970-01-01
              相关资源
              最近更新 更多