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

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

2

我是新手,但上面的一些答案过于复杂了,所以这里提供一个替代方案。

注意:只要0-9是连续的(根据标准应该是这样),这个方案就可以过滤掉除了数字和空格以外的其他字符。因为我们知道0-9是连续的且一个字符实际上是一个整数,所以可以按照以下方式操作。

编辑:我没有注意到发帖者也想包含空格,所以我做了修改...

#include <cstdio>
#include <cstring>

void numfilter(char * buff, const char * string)
{
  do
  { // According to standard, 0-9 should be contiguous in system int value.
    if ( (*string >= '0' && *string <= '9') || *string == ' ')
      *buff++ = *string;
  } while ( *++string );
  *buff++ = '\0'; // Null terminate
}

int main()
{
  const char *string = "(555) 555-5555";
  char buff[ strlen(string) + 1 ];

  numfilter(buff, string);
  printf("%s\n", buff);

return 0;
}

以下是过滤提供的字符。
#include <cstdio>
#include <cstring>

void cfilter(char * buff, const char * string, const char * toks)
{
  const char * tmp;  // So we can keep toks pointer addr.
  do
  {
    tmp = toks;
    *buff++ = *string; // Assume it's correct and place it.
    do                 // I can't think of a faster way.
    {
      if (*string == *tmp)
      {
        buff--;  // Not correct, pull back and move on.
        break;
      }
    }while (*++tmp);
  }while (*++string);

  *buff++ = '\0';  // Null terminate
}

int main()
{
  char * string = "(555) 555-5555";
  char * toks = "()-";
  char buff[ strlen(string) + 1 ];

  cfilter(buff, string, toks);
  printf("%s\n", buff);

  return 0;
}

那并不是 OP 想要的;它也删除了空格。 - Andrew Barber

2

对于那些更喜欢简洁、易读的lambda编码风格的人...

这个例子会从一个宽字符串中移除所有非字母数字和空格字符。你可以与其他ctype.h帮助函数混合使用,以去除看起来复杂的基于字符的测试。

(我不确定这些函数如何处理CJK语言,所以请小心.)

    // Boring C loops: 'for(int i=0;i<str.size();i++)' 
    // Boring C++ eqivalent: 'for(iterator iter=c.begin; iter != c.end; ++iter)'

看看这个是否比吵闹的C/C++ for/iterator循环更容易理解:

TSTRING label = _T("1.   Replen & Move  RPMV");
TSTRING newLabel = label;
set<TCHAR> badChars; // Use ispunct, isalpha, isdigit, et.al. (lambda version, with capture list parameter(s) example; handiest thing since sliced bread)
for_each(label.begin(), label.end(), [&badChars](TCHAR n){
    if (!isalpha(n) && !isdigit(n))
        badChars.insert(n);
});

for_each(badChars.begin(), badChars.end(), [&newLabel](TCHAR n){
    newLabel.erase(std::remove(newLabel.begin(), newLabel.end(), n), newLabel.end());
});

运行此代码后的newLabel结果为:“1ReplenMoveRPMV

这只是学术上的问题,因为如果你已经确定了哪些字符是“badChars”,将lambda0(第一个for_each)中的“if”逻辑合并到单个lambda1(第二个for_each)中显然更加精确、简洁和高效。


感谢@Eric Z的回答,提到并使用了方便的Erase-remove惯用语。http://en.wikipedia.org/wiki/Erase-remove_idiom - Darrin

2

使用 std::wstringwchar_t(需要 Unicode 标头):

//#include <tchar.h>
std::wstring phone(L"(555) 555-5555");

更好的静态范围初始化器是下一个,不必以完全相同的方式设置badChars2。这样做太过复杂,更偏向于学术性质。

const wchar_t *tmp = L"()-"; 
const std::set<wchar_t> badChars2(tmp,tmp + sizeof(tmp)-1);

简单、精炼的Lambda表达式:

  1. Uses phone in the lambda capture list.
  2. Uses Erase-remove idiom
  3. Removes all bad characters from phone

    for_each(badChars2.begin(), badChars2.end(), [&phone](wchar_t n){
         phone.erase(std::remove(phone.begin(), phone.end(), n), phone.end());
    });
    wcout << phone << endl;
    
输出: "555 5555555"

1
很多好的答案,这是另一种清理数字字符串的方法,不是通过删除字符,而是将数字移出。
string str("(555) 555-5555"), clean;
for (char c : str)
    if (c >= 48 and c <= 57)
        clean.push_back(c);

-1
从C++20开始,您可以在std::basic_string中使用erase/erase_if,它基本上是擦除-移除惯用法的便利包装器。
std::erase(phone, '('); 

并且

std::erase_if(phone, [](char x) { 
                        return x == '(' or x == ')' or x == '-'; 
                     });

请注意,这些函数还会返回已删除的字符数。

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