11

我正在尝试查找是否有更好的方法来检查字符串是否具有特殊字符。就我而言,除字母数字和“_”之外的任何内容都被视为特殊字符。目前,我有一个包含特殊字符的字符串,例如 std::string = "!@#$%^&"。然后我使用 std::find_first_of () 算法检查字符串中是否存在任何特殊字符。

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

4

9 回答 9

17

尝试:

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);   
于 2011-07-07T02:50:33.087 回答
4

我想我会做一些不同的工作,把它std::string当作一个集合,并使用一种算法。使用 C++0x lambda,它看起来像这样:

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

至少当您处理char(not 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 */

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

正式地,C 标准表示尝试将范围放入像这样的扫描集转换是不可移植的(除了扫描集的开头或结尾之外的任何地方都有一个“-”给出实现定义的行为)。甚至有一些编译器(来自 Borland)会因此而失败——它们会将A-Z三个可能的字符视为完全匹配,“A”、“-”和“Z”。大多数当前的编译器(或更准确地说,标准库实现)采用这种假设的方法:“AZ”匹配任何大写字符。

于 2011-07-07T05:57:23.583 回答
3

使用标准 C 或 C++ 无法使用字符范围来做到这一点,您必须列出所有字符。对于 C 字符串,您可以使用strspn(3)andstrcspn(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成员函数。

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

于 2011-07-07T02:58:45.863 回答
3

您需要考虑的第一件事是“仅此 ASCII”吗?如果你的回答是肯定的,我会鼓励你真正考虑是否应该只允许 ASCII。我目前在一家公司工作,该公司在进入国外市场时确实有些头疼,因为我们从一开始就没有考虑支持 unicode。

话虽如此,ASCII 使检查非字母数字变得非常容易。看一下ascii图表。

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

  • 遍历每个字符
  • 检查字符是否为十进制值 48 - 57、65 - 90、97 - 122 或 95(下划线)
于 2011-07-07T02:59:33.900 回答
1

函数(宏)受区域设置的影响,但您应该调查来自or的isalnum()亲戚。<ctype.h><cctype>

于 2011-07-07T02:51:15.897 回答
0

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

于 2011-07-07T02:56:52.790 回答
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';
}
于 2011-07-07T03:10:40.060 回答
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功能进行高度自定义。

于 2012-09-23T07:59:28.800 回答
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()检查它是否是数字。

于 2021-01-26T03:53:48.013 回答