【问题标题】:how to check if given c++ string or char* contains only digits?如何检查给定的 c++ 字符串或 char* 是否仅包含数字?
【发布时间】:2012-02-11 21:50:23
【问题描述】:

或者反过来找第一个非数字字符。

相同的函数适用于 string 和 char* 吗?

【问题讨论】:

    标签: c++ string pattern-matching


    【解决方案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 &lt;regex&gt;

      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 段,以下适用于来自 &lt;ctype.h&gt; 的函数的参数:

        ... 在所有情况下,参数都是int,其值应为 可表示为unsigned char 或应等于宏EOF 的值。如果 参数有任何其他值,行为未定义。

        不幸的是,C++ 标准没有指定char 是无符号类型。相反,它在 ISO/IEC 14882:2011 3.9.1 [basic.fundamental] 第 1 段中指定:

        ... char 对象是否可以保存负值是实现定义的。 ...

        显然,负值不能表示为unsigned char。也就是说,如果char 在实现上使用签名类型(实际上有几个这样做,例如,它是在 MacOS 上使用 gcc 或 clang 签名的),那么调用任何&lt;ctype.h&gt; 函数都会导致危险未定义的行为。

        现在,为什么转换为 unsigned char 会做正确的事情?

        根据 4.7 [conv.integral] 第 2 段:

        如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n,其中 n 是用于表示无符号类型的位数)。 [ 注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 ——尾注]

        也就是说,从 [可能] 签名的 charunsigned char 的转换是明确定义的,并导致结果在 &lt;ctype.h&gt; 函数的允许范围内。

        【讨论】:

        • 我不确定我是否理解您:您是否说将char 转换为unsigned char,可能会产生溢出或UB,比依靠isdigit() 检查@987654342 更好。 @ 属于['0'..'9'],具体以int 作为输入?如果可能的话,任何引用或理由都可能会有所帮助。
        • charunsigned 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 函数(来自&lt;cctype&gt;&lt;locale&gt; 标头)。 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")
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-11-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-19
              • 1970-01-01
              相关资源
              最近更新 更多