如何在C++中从字符串中删除特定字符?

110
例如,我让用户输入一个电话号码。
cout << "Enter phone number: ";
INPUT: (555) 555-5555
cin >> phone;
我想从字符串中移除"("、")"和"-"字符。我查看了字符串的删除、查找和替换函数,但是我只看到它们基于位置进行操作。
是否有一种可以接受字符参数(例如"("),并将其从字符串中所有实例删除的字符串函数?
15个回答

153
   string str("(555) 555-5555");

   char chars[] = "()-";

   for (unsigned int i = 0; i < strlen(chars); ++i)
   {
      // you need include <algorithm> to use general algorithms like std::remove()
      str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
   }

   // output: 555 5555555
   cout << str << endl;

要将其用作函数

void removeCharsFromString( string &str, char* charsToRemove ) {
   for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
      str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
   }
}
//example of usage:
removeCharsFromString( str, "()-" );

6
这个是怎么工作的?使用erase和remove不是一个双重否定吗?对我来说,这意味着:“删除在()内没有-的位置上的字符。”由于每个都是一次完成的,难道不应该删除所有字符吗?我已经阅读了两个函数的文档,但这对我来说毫无意义。http://www.cplusplus.com/reference/algorithm/remove/ http://www.cplusplus.com/reference/string/string/erase/ - Brent
25
@Brent和未来读者,这是Erase-remove idiom。简单来说,std::remove将未删除的项移动到向量的前面,并返回一个指向最后一个未删除项的迭代器。然后,std::erase从该迭代器到结尾修剪向量。 - chwarr
1
对于真正的C++版本,我认为我们应该使用string chars("()-");,然后使用.length()方法获取长度和.at(i)方法访问字符 :) 函数化fiddle - http://ideone.com/tAZt5I - jave.web
2
使用作为函数: http://ideone.com/XOROjq - 使用<iostream> <algorithm> <cstring> - jave.web
2
你最好缓存 strlen(chars),因为它的复杂度是 O(n) - fnc12
显示剩余4条评论

42
我想从字符串中移除 "(", ")", 和 "-" 这些字符。
你可以使用 std::remove_if() 算法来仅移除指定的字符:
#include <iostream>
#include <algorithm>
#include <string>

bool IsParenthesesOrDash(char c)
{
    switch(c)
    {
    case '(':
    case ')':
    case '-':
        return true;
    default:
        return false;
    }
}

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), &IsParenthesesOrDash), str.end());
    std::cout << str << std::endl; // Expected output: 555 5555555
}

std::remove_if()算法需要一个谓词,它可以是函数指针,就像上面的代码片段一样。

你还可以传递一个函数对象(重载函数调用 () 运算符的对象)。这使我们可以创建一个更加通用的解决方案:

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

class IsChars
{
public:
    IsChars(const char* charsToRemove) : chars(charsToRemove) {};

    bool operator()(char c)
    {
        for(const char* testChar = chars; *testChar != 0; ++testChar)
        {
            if(*testChar == c) { return true; }
        }
        return false;
    }

private:
    const char* chars;
};

int main()
{
    std::string str("(555) 555-5555");
    str.erase(std::remove_if(str.begin(), str.end(), IsChars("()- ")), str.end());
    std::cout << str << std::endl; // Expected output: 5555555555
}
你可以使用字符串"()- "指定要删除的字符。在上面的示例中,我添加了一个空格,以便除括号和破折号外还删除空格。

你还可以使用 ispunct(int c) - MSalters
优秀的实现。这个方法运行得非常完美,还有很多空间进行进一步的动态调整。感谢您的回复,MSalters,我也会查找ispunct(int c)函数并报告我的工作情况。 - SD.

14

已经提到了remove_if()函数。但是,在C++0x中,你可以使用一个lambda表达式来指定它的断言。

以下是一个示例,其中展示了三种不同的筛选方式。还包括“copy”函数版本,以处理与const相关的情况或者不想修改原始数据的情况。

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

string& remove_chars(string& s, const string& chars) {
    s.erase(remove_if(s.begin(), s.end(), [&chars](const char& c) {
        return chars.find(c) != string::npos;
    }), s.end());
    return s;
}
string remove_chars_copy(string s, const string& chars) {
    return remove_chars(s, chars);
}

string& remove_nondigit(string& s) {
    s.erase(remove_if(s.begin(), s.end(), [](const char& c) {
        return !isdigit(c);
    }), s.end());
    return s;
}
string remove_nondigit_copy(string s) {
    return remove_nondigit(s);
}

string& remove_chars_if_not(string& s, const string& allowed) {
    s.erase(remove_if(s.begin(), s.end(), [&allowed](const char& c) {
        return allowed.find(c) == string::npos;
    }), s.end());
    return s;
}
string remove_chars_if_not_copy(string s, const string& allowed) {
    return remove_chars_if_not(s, allowed);
}

int main() {
    const string test1("(555) 555-5555");
    string test2(test1);
    string test3(test1);
    string test4(test1);
    cout << remove_chars_copy(test1, "()- ") << endl;
    cout << remove_chars(test2, "()- ") << endl;
    cout << remove_nondigit_copy(test1) << endl;
    cout << remove_nondigit(test3) << endl;
    cout << remove_chars_if_not_copy(test1, "0123456789") << endl;
    cout << remove_chars_if_not(test4, "0123456789") << endl;
}

我应该真正使用const string::value_type&,而不是const char& c。但在这种情况下,这并不是什么大问题。 - Shadow2531
1
这是一个非常彻底的实现。我很感激并将使用这个实现。 - SD.

9

如果您感兴趣,这里有一种不同的解决方案。它使用了C++11中的新For范围。

string str("(555) 555-5555");
string str2="";

for (const auto c: str){

    if(!ispunct(c)){

        str2.push_back(c);
    }
}

str = str2;
//output: 555 5555555
cout<<str<<endl;

1
(1) 不需要初始化 str2。 (2) 使用 std::move(str2) 更加高效。 - Ajay

7

恐怕std::string没有这样一个成员,不过您可以轻松编写这种函数。这可能不是最快的解决方案,但是足以满足要求:

std::string RemoveChars(const std::string& source, const std::string& chars) {
   std::string result="";
   for (unsigned int i=0; i<source.length(); i++) {
      bool foundany=false;
      for (unsigned int j=0; j<chars.length() && !foundany; j++) {
         foundany=(source[i]==chars[j]);
      }
      if (!foundany) {
         result+=source[i];
      }
   }
   return result;
}

编辑:阅读下面的答案,我理解它更为普遍,不仅适用于检测数字。上述解决方案将省略第二个参数字符串中传递的每个字符。 例如:

std::string result=RemoveChars("(999)99-8765-43.87", "()-");

将导致

99999876543.87

5

boost::is_any_of

该函数用于从一个字符串中删除出现在另一个给定字符串中的所有字符:

#include <cassert>

#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>

int main() {
    std::string str = "a_bc0_d";
    str.erase(boost::remove_if(str, boost::is_any_of("_0")), str.end());
    assert((str == "abcd"));
}

在Ubuntu 16.04和Boost 1.58中进行了测试。


4
using namespace std;


// c++03
string s = "(555) 555-5555";
s.erase(remove_if(s.begin(), s.end(), not1(ptr_fun(::isdigit))), s.end());

// c++11
s.erase(remove_if(s.begin(), s.end(), ptr_fun(::ispunct)), s.end());

注意: 你可能需要写成ptr_fun<int, int>而不是简单的ptr_fun


这为什么不是被选中的答案? - user3240688
请注意,C++11中已弃用std::ptr_fun,并将在C++17中删除std::not1。您可以使用std::crefstd::function(或lambda表达式)。 - Roi Danton

4

是的,您可以使用isdigit()函数来检查数字 :)

这里是:

#include <iostream>
#include <cctype>
#include <string.h>

using namespace std;

int main(){

  char *str = "(555) 555-5555";
  int len = strlen(str);

  for (int i=0; i<len; i++){
      if (isdigit(*(str+i))){
        cout << *(str+i);
      }
  }

  cout << endl;


return 0;   
}

希望能对您有所帮助 :)

这可以被修改以删除返回false的元素。谢谢。 - SD.

3
如果你有使用支持变参模板的编译器,你可以使用以下代码进行操作:
#include <iostream>
#include <string>
#include <algorithm>

template<char ... CharacterList>
inline bool check_characters(char c) {
    char match_characters[sizeof...(CharacterList)] = { CharacterList... };
    for(int i = 0; i < sizeof...(CharacterList); ++i) {
        if(c == match_characters[i]) {
            return true;
        }
    }
    return false;
}

template<char ... CharacterList>
inline void strip_characters(std::string & str) {
    str.erase(std::remove_if(str.begin(), str.end(), &check_characters<CharacterList...>), str.end());
}

int main()
{
    std::string str("(555) 555-5555");
    strip_characters< '(',')','-' >(str);
    std::cout << str << std::endl;
}

2

这里有另一种选择:

template<typename T>
void Remove( std::basic_string<T> & Str, const T * CharsToRemove )
{
    std::basic_string<T>::size_type pos = 0;
    while (( pos = Str.find_first_of( CharsToRemove, pos )) != std::basic_string<T>::npos )
    {
        Str.erase( pos, 1 ); 
    }
}

std::string a ("(555) 555-5555");
Remove( a, "()-");

支持 std::string 和 std::wstring


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接