我认为我会稍微不同地处理这个任务,将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
(而不是wchar_t
)时,isalnum
通常会使用表查找,因此通常比基于find_first_of
的任何内容要快得多(后者通常会使用线性搜索)。 换句话说,这是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跳过所有连续的非特殊字符(但由于
*
,不会将结果分配给任何内容),然后我们尝试读取一个更多的字符。如果成功,则意味着至少有一个字符是未被跳过的,因此我们必须至少有一个特殊字符。如果失败,则表示scanset转换匹配整个字符串,因此所有字符都是“非特殊”的。
正式地说,C标准规定,尝试在类似这样的scanset转换中放置范围是不可移植的(除了在scanset的开头或结尾处放置“-”以外的任何地方都会产生实现定义的行为)。甚至还有一些编译器(来自Borland)会因此而失败 - 它们将把
A-Z
视为仅匹配三个可能的字符,即“A”,“-”和“Z”。大多数当前的编译器(或更准确地说,标准库实现)采用了这种做法: "A-Z" 匹配任何大写字母。