如何检查给定的 c++ 字符串或 char* 是不是仅包含数字?
Posted
技术标签:
【中文标题】如何检查给定的 c++ 字符串或 char* 是不是仅包含数字?【英文标题】:how to check if given c++ string or char* contains only digits?如何检查给定的 c++ 字符串或 char* 是否仅包含数字? 【发布时间】:2012-02-11 21:50:23 【问题描述】:或者反过来找第一个非数字字符。
相同的函数适用于 string 和 char* 吗?
【问题讨论】:
【参考方案1】:从cplusplus.com你可以使用如下的isdigit函数:
// isdigit example (C++)
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::isdigit
#include <sstream> // std::stringstream
int main ()
std::locale loc;
std::string str="1776ad";
if (isdigit(str[0],loc))
int year;
std::stringstream(str) >> year;
std::cout << "The year that followed " << year << " was " << (year+1) << ".\n";
return 0;
注意:isdigit 有 2 种类型,另一种版本是本地独立的和基于 ASCII 的。
【讨论】:
【参考方案2】:#include <regex>
std::string string( "I only have 3 dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // true
和
std::string string( "I only have three dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // false
【讨论】:
【参考方案3】:已经有几个人提到使用isdigit()
。但是请注意,这并非完全无关紧要,因为可以对char
进行签名,这会导致将负值传递给isdigit()
。但是,此函数只能取正值。也就是说,你想要类似的东西:
if (s.end() == std::find_if(s.begin(), s.end(),
[](unsigned char c)->bool return !isdigit(c); ))
std::cout << "string '" << s << "' contains only digits\n";
似乎转换为unsigned char
的原因并不明显。因此,以下是各自标准中的相关引述:
根据 ISO/IEC 9899:2011(或 ISO/IEC 9899:1999)7.4 第 1 段,以下适用于来自 <ctype.h>
的函数的参数:
... 在所有情况下,参数都是
int
,其值应为 可表示为unsigned char
或应等于宏EOF
的值。如果 参数有任何其他值,行为未定义。
不幸的是,C++ 标准没有指定char
是无符号类型。相反,它在 ISO/IEC 14882:2011 3.9.1 [basic.fundamental] 第 1 段中指定:
...
char
对象是否可以保存负值是实现定义的。 ...
显然,负值不能表示为unsigned char
。也就是说,如果char
在实现上使用签名类型(实际上有几个这样做,例如,它是在 MacOS 上使用 gcc 或 clang 签名的),那么调用任何<ctype.h>
函数都会导致危险未定义的行为。
现在,为什么转换为 unsigned char
会做正确的事情?
根据 4.7 [conv.integral] 第 2 段:
如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n,其中 n 是用于表示无符号类型的位数)。 [ 注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 ——尾注]
也就是说,从 [可能] 签名的 char
到 unsigned char
的转换是明确定义的,并导致结果在 <ctype.h>
函数的允许范围内。
【讨论】:
我不确定我是否理解您:您是否说将char
转换为unsigned char
,可能会产生溢出或UB,比依靠isdigit()
检查@987654342 更好。 @ 属于['0'..'9']
,具体以int
作为输入?如果可能的话,任何引用或理由都可能会有所帮助。
从char
到unsigned char
的转换不会溢出或任何东西。即使char
已签名并且字符在负数范围内,它将保留原始位,但会在isdigit()
的定义范围内产生一个值。相关引用在 C 的 7.4 第 1 段中。【参考方案4】:
与 Misha 的回答相同,但更正确:sscanf(buf, "%*u%*c")==1
。
如果%d
数字提取失败,scanf
返回 0,如果 %c
捕获的数字后面还有任何内容,则返回 2。而且由于*
阻止了值的存储,因此您甚至不会出现溢出。
【讨论】:
这是迄今为止最好的答案。它适用于有符号/无符号、浮点与整数等。【参考方案5】:当然,有很多方法可以只测试字符串中的数字字符。两种可能的方法是:
bool is_digits(const std::string &str)
return str.find_first_not_of("0123456789") == std::string::npos;
或
bool is_digits(const std::string &str)
return std::all_of(str.begin(), str.end(), ::isdigit); // C++11
【讨论】:
为什么这里是双冒号 isdigit ?没有它就无法编译,std::isdigit
也不起作用。
@Dfr:有多个isdigit
函数(来自<cctype>
和<locale>
标头)。 See this related answer.
c++11 的方式实在是太棒了 :)
@Jichao:你是对的,但那将是一个不同的问题。
@AmitUpadhyay:我使用引用来避免复制传递的std::string
参数(复制可能会很昂贵)。它们也是const
,以确保我不会修改调用者的变量。以这种方式使用 const 引用在 C++ 编程中非常常见。【参考方案6】:
如果严格要求您可以准确找到第一个非字符数字的位置,那么您必须检查每个字符。如果没有,我会使用这样的东西:
unsigned safe_atoi(const std::string& a)
std::stringstream s(a);
unsigned b;
s >> b;
return b;
【讨论】:
【参考方案7】:cctype
头文件有很多字符分类函数,您可以对字符串中的每个字符使用这些函数。对于数字检查,应为 isdigit
。
下面的程序展示了如何检查 C 或 C++ 字符串的每个字符(检查实际字符的过程几乎相同,唯一真正的区别是如何获取长度):
#include <iostream>
#include <cstring>
#include <cctype>
int main (void)
const char *xyzzy = "42x";
std::cout << xyzzy << '\n';
for (int i = 0; i < std::strlen (xyzzy); i++)
if (! std::isdigit (xyzzy[i]))
std::cout << xyzzy[i] << " is not numeric.\n";
std::string plugh ("3141y59");
std::cout << plugh << '\n';
for (int i = 0; i < plugh.length(); i++)
if (! std::isdigit (plugh[i]))
std::cout << plugh[i] << " is not numeric.\n";
return 0;
【讨论】:
【参考方案8】:isdigit(int)
告诉您字符是否为数字。如果你打算假设 ASCII 和 base 10,你也可以使用:
int first_non_digit_offset= strspn(string, "0123456789")
【讨论】:
以上是关于如何检查给定的 c++ 字符串或 char* 是不是仅包含数字?的主要内容,如果未能解决你的问题,请参考以下文章
用于检查 char 数组是不是包含 Java 中用户给定字母的 if 语句