如何在C ++中从字符串中剥离所有非字母数字字符?

How to strip all non alphanumeric characters from a string in c++?

我正在编写一个软件,它要求我使用libcurl处理从网页中获取的数据。 当我得到数据时,由于某种原因,它中有额外的换行符。 我需要找出一种只允许使用字母,数字和空格的方法。 并删除所有其他内容,包括换行符。 有没有简单的方法可以做到这一点? 谢谢。


编写一个接受char并返回true的函数(如果要删除该字符),或者返回false(如果要保留它):

1
bool my_predicate(char c);

然后使用std::remove_if算法从字符串中删除不需要的字符:

1
2
std::string s ="my data";
s.erase(std::remove_if(s.begin(), s.end(), my_predicate), s.end());

根据您的要求,您也许可以使用标准库谓词之一,例如std::isalnum,而不是编写自己的谓词(您说过您需要匹配字母数字字符和空格,因此也许这不完全适合你需要)。

如果要使用标准库std::isalnum函数,则需要强制转换以消除C标准库头文件(您要使用的头)中的std::isalnum函数和std::isalnum之间的歧义。在C ++标准库标头中(不是您要使用的标头,除非您要执行特定于语言环境的字符串处理):

1
s.erase(std::remove_if(s.begin(), s.end(), (int(*)(int))std::isalnum), s.end());

这对于任何序列容器(包括std::stringstd::vectorstd::deque)都同样有效。该惯用语通常称为"擦除/删除"惯用语。 std::remove_if算法也适用于普通数组。 std::remove_if仅对序列进行一次遍历,因此具有线性时间复杂度。


在没有传递一元参数的情况下,std::isalnum的先前用法将无法与std::ptr_fun一起编译,因此具有lambda函数的此解决方案应封装正确的答案:

1
2
s.erase(std::remove_if(s.begin(), s.end(),
[]( auto const& c ) -> bool { return !std::isalnum(c); } ), s.end());


如果您使用的是string,则可以始终循环浏览并仅erase所有非字母数字字符。

1
2
3
4
5
6
7
8
9
10
11
#include <cctype>

size_t i = 0;
size_t len = str.length();
while(i < len){
    if (!isalnum(str[i]) || str[i] == ' '){
        str.erase(i,1);
        len--;
    }else
        i++;
}

使用标准库的更好的人可能可以无循环执行此操作。

如果仅使用char缓冲区,则可以循环浏览,如果一个字符不是字母数字,则将所有字符向后移一个(以覆盖有问题的字符):

1
2
3
4
5
6
#include <cctype>

size_t buflen = something;
for (size_t i = 0; i < buflen; ++i)
    if (!isalnum(buf[i]) || buf[i] != ' ')
        memcpy(buf[i], buf[i + 1], --buflen - i);


1
2
3
4
5
6
7
8
#include <cctype>
#include <string>
#include <functional>

std::string s ="Hello World!";
s.erase(std::remove_if(s.begin(), s.end(),
    std::not1(std::ptr_fun(std::isalnum)), s.end()), s.end());
std::cout << s << std::endl;

结果是:

1
"HelloWorld"

您使用isalnum来确定每个字符是否都是字母数字,然后使用ptr_fun将函数传递给not1,而不是返回值,只剩下所需的字母数字内容。


remove_copy_if标准算法非常适合您的情况。


下面的代码对于给定的字符串s应该可以正常工作。它利用了库。

1
2
std::string s("He!!llo  Wo,@rld! 12 453");
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return !std::isalnum(c); }), s.end());


只是扩展了James McNellis的代码。他的功能是删除数字字符而不是非数字字符。

从字符串中删除非数字字符。 (数字=字母或数字)

  • 声明一个函数(如果传递的char不是alnum,则isalnum返回0)

    1
    2
    3
    bool isNotAlnum(char c) {
        return isalnum(c) == 0;
    }
  • 然后写这个

    1
    s.erase(remove_if(s.begin(), s.end(), isNotAlnum), s.end());

那么您的字符串只能包含数字字符。


您可以通过这种方式使用删除-擦除算法-

1
2
// Removes all punctuation      
s.erase( std::remove_if(s.begin(), s.end(), &ispunct), s.end());

提到的解决方案

1
s.erase( std::remove_if(s.begin(), s.end(), &std::ispunct), s.end());

非常好,但不幸的是不适用于'?'等字符在Visual Studio(调试模式)中,由于以下原因:

1
_ASSERTE((unsigned)(c + 1) <= 256)

在isctype.c中

所以,我建议这样的事情:

1
2
3
4
5
6
inline int my_ispunct( int ch )
{
    return std::ispunct(unsigned char(ch));
}
...
s.erase( std::remove_if(s.begin(), s.end(), &my_ispunct), s.end());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void remove_spaces(string data)
{ int i=0,j=0;
    while(i<data.length())
    {
        if (isalpha(data[i]))
        {
        data[i]=data[i];
        i++;
        }
        else
            {
            data.erase(i,1);}
    }
    cout<<data;
}

以下对我有用。

1
2
str.erase(std::remove_if(str.begin(), str.end(), &ispunct), str.end());
str.erase(std::remove_if(str.begin(), str.end(), &isspace), str.end());