如何有效地检查字符串是否在C ++中具有特殊字符?

时间:2011-07-07 02:46:14

标签: c++ string whitelist c-strings

我试图找出是否有更好的方法来检查字符串是否有特殊字符。在我的例子中,除了字母数字和'_'之外的任何东西都被认为是一个特殊字符。目前,我有一个包含特殊字符的字符串,例如std :: string =“!@#$%^&”。然后我使用std :: find_first_of()算法来检查字符串中是否存在任何特殊字符。

我想知道如何基于白名单来做到这一点。我想在字符串中指定小写/大写字符,数字和下划线(我不想列出它们。有没有什么方法可以指定某种类型的ascii范围,如[a-zA-Z0-9_] )。我怎样才能做到这一点?然后我计划使用std :: find_first_not_of()。通过这种方式,我可以提到我真正想要的东西并检查相反的情况。

9 个答案:

答案 0 :(得分:13)

尝试:

std::string  x(/*Load*/);
if (x.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_") != std::string::npos)
{
    std::cerr << "Error\n";
}

或尝试提升正则表达式:

// Note: \w matches any word character `alphanumeric plus "_"`
boost::regex test("\w+", re,boost::regex::perl);
if (!boost::regex_match(x.begin(), x.end(), test)
{
    std::cerr << "Error\n";
}

// The equivalent to \w should be:
boost::regex test("[A-Za-z0-9_]+", re,boost::regex::perl);   

答案 1 :(得分:3)

使用标准C或C ++无法使用字符范围来执行此操作,您必须列出所有字符。对于C字符串,您可以使用strspn(3)strcspn(3)来查找字符串中的第一个字符,该字符串是给定字符集的成员或不是给定字符集的成员。例如:

// Test if the given string has anything not in A-Za-z0-9_
bool HasSpecialCharacters(const char *str)
{
    return str[strspn(str, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")] != 0;
}

对于C ++字符串,您可以等效地使用find_first_offind_first_not_of成员函数。

另一种选择是使用<ctype.h>中的isalnum(3) and related functions来测试给定字符是否为字母数字;请注意,这些函数是依赖于语言环境的,因此它们的行为可以(并且确实)在其他语言环境中更改。如果您不想要这种行为,请不要使用它们。如果你确实选择使用它们,你还必须单独测试下划线,因为没有测试“字母,数字或下划线”的功能,你还需要编写自己的循环来搜索字符串(或者使用std::find和适当的函数对象。)

答案 2 :(得分:3)

您需要考虑的第一件事是“仅限此ASCII”吗?如果您回答是,我建议您真正考虑是否应该仅允许ASCII。我目前正在为一家真正有进入国外市场的公司工作,因为我们不认为从一开始就支持unicode。

话虽这么说,ASCII可以很容易地检查非alpha数字。看看ascii图表。

http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters

  • 遍历每个角色
  • 检查字符是否为十进制值48 - 57,65 - 90,97 - 122或95(下划线)

答案 3 :(得分:3)

我认为我的工作略有不同,将std::string视为一个集合,并使用算法。使用C ++ 0x lambda,它看起来像这样:

bool has_special_char(std::string const &str) {
    return std::find_if(str.begin(), str.end(),
        [](char ch) { return !(isalnum(ch) || ch == '_'); }) != str.end();
}

至少在您处理char(而非wchar_t)时,isalnum通常会使用表格查找,因此通常会(相当快)更快比基于find_first_of的任何东西(通常使用线性搜索)。 IOW,这是O(N)(N = str.size()),其中基于find_first_of的东西将是O(N * M),(N = str.size(),M = pattern.size ())。

如果你想用纯C做这个工作,你可以使用scanf进行扫描集转换,这在理论上是不可移植的,但基本上所有最近/流行的编译器都支持:

char junk;
if (sscanf(str, "%*[A-Za-z0-9_]%c", &junk))
    /* it has at least one "special" character
else
    /* no special characters */

这里的基本思路非常简单:scanset跳过所有连续的非特殊字符(但由于*而没有将结果分配给任何东西),然后我们尝试再读一个字符。如果成功,则表示至少有一个跳过的字符,因此我们必须至少有一个特殊字符。如果失败,则表示扫描集转换与整个字符串匹配,因此所有字符都是“非特殊”。

正式地说,C标准说试图在这样的扫描集转换中放置一个范围是不可移植的(a' - '在任何地方,但扫描集的开头或结尾给出了实现定义的行为)。甚至有一些编译器(来自Borland)会因此失败 - 他们会将A-Z视为恰好匹配三个可能的字符,'A',' - '和'Z'。大多数当前的编译器(或更准确地说,标准库实现)采用这种假设的方法:“A-Z”匹配任何大写字符。

答案 4 :(得分:1)

功能(宏)受区域设置的约束,但您应该调查来自isalnum()<ctype.h>的{​​{1}}及亲属。

答案 5 :(得分:0)

我会在这里使用内置的C工具。迭代字符串中的每个字符,检查它是_还是isalpha(ch)是真的。如果是,那么它是有效的,否则它是一个特殊的角色。

答案 6 :(得分:0)

如果你想要这个,但是不想全力以赴并使用正则表达式,并且给你测试的是ASCII字符 - 只需创建一个函数来生成find_first_not_of的字符串...

#include <iostream>
#include <string>

std::string expand(const char* p)
{
    std::string result;
    while (*p)
        if (p[1] == '-' && p[2])
        {
            for (int c = p[0]; c <= p[2]; ++c)
                result += (char)c;
            p += 3;
        }
        else
            result += *p++;
    return result;
}

int main()
{
    std::cout << expand("A-Za-z0-9_") << '\n';
}

答案 7 :(得分:0)

使用

    s.erase(std::remove_if(s.begin(), s.end(), my_predicate), s.end());

    bool my_predicate(char c)
    {
     return !(isalpha(c) || c=='_');
    }

会给你一个干净的字符串s

擦除会将所有特殊字符剥离掉,并且可以高度自定义 使用my_predicate函数。

答案 8 :(得分:0)

你可以这样使用:

#include <ctype>

for(int i=0;i<s.length();i++){
    if( !std::isalpha(s[i]) && !std::isdigit(s[i]) && s[i]!='_')
          return false
}

isalpha() 函数检查它是否是字母数字,isdigit() 函数检查它是否是数字。