45

当我使用 时getline,我会输入一堆字符串或数字,但如果它不是数字,我只希望 while 循环输出“单词”。那么有没有办法检查“单词”是否是一个数字?我知道我可以atoi()用于 C 字符串,但是对于字符串类的字符串呢?

int main () {
  stringstream ss (stringstream::in | stringstream::out);
  string word;
  string str;
  getline(cin,str);
  ss<<str;
  while(ss>>word)
    {
      //if(    )
        cout<<word<<endl;
    }
}
4

11 回答 11

74

另一个版本...

使用strtol,将其包装在一个简单的函数中以隐藏其复杂性:

inline bool isInteger(const std::string & s)
{
   if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;

   char * p;
   strtol(s.c_str(), &p, 10);

   return (*p == 0);
}

为什么strtol

就我喜欢 C++ 而言,有时 C API 是我所关心的最佳答案:

  • 对于被授权失败的测试,使用异常是矫枉过正的
  • 当 C 标准库有一个鲜为人知的专用函数来完成这项工作时,词法转换创建的临时流对象是过度杀伤和效率低下的。

它是如何工作的 ?

strtol乍一看似乎很原始,因此解释将使代码更易于阅读:

strtol将解析字符串,在第一个不能被视为整数一部分的字符处停止。如果您提供p(如我上面所做的那样),它会设置p在第一个非整数字符处。

我的推理是如果p没有设置到字符串的末尾(0字符),那么字符串中有一个非整数字符s,意思s是不是一个正确的整数。

第一个测试是为了消除极端情况(前导空格、空字符串等)。

当然,此功能应该根据您的需要进行定制(前导空格是错误的吗?等等)。

资料来源:

请参阅以下网址的说明strtolhttp ://en.cppreference.com/w/cpp/string/byte/strtol 。

另请参阅strtol的姐妹函数(strtodstrtoul等)的描述。

于 2010-05-16T20:09:24.127 回答
70

如果输入是数字加文本,则接受的答案将给出误报,因为“stol”将转换第一个数字并忽略其余数字。

我最喜欢下面的版本,因为它是一个很好的单行代码,不需要定义函数,你可以在需要的地方复制和粘贴。

#include <string>

...

std::string s;

bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);

编辑:如果你喜欢这个实现,但你确实想将它用作一个函数,那么应该这样做:

bool has_only_digits(const string s){
  return s.find_first_not_of( "0123456789" ) == string::npos;
}
于 2016-06-16T16:42:20.383 回答
17

你可以试试boost::lexical_castbad_lexical_cast如果失败则抛出异常。

在你的情况下:

int number;
try
{
  number = boost::lexical_cast<int>(word);
}
catch(boost::bad_lexical_cast& e)
{
  std::cout << word << "isn't a number" << std::endl;
}
于 2010-05-16T18:03:56.683 回答
9

如果您只是检查是否word是数字,那并不难:

#include <ctype.h>

...

string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
    isNumber &&= isdigit(*k);

根据需要进行优化。

于 2010-05-16T18:20:36.790 回答
5

使用全能的 C stdio/string 函数:

int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);

if (scan_value == 0)
    // does not start with integer
else
    // starts with integer
于 2013-01-23T20:52:15.980 回答
4

好的,在我看来,您有 3 个选项。

1:如果您只想检查数字是否为整数,而不关心转换它,而只是希望将其保留为字符串并且不关心潜在的溢出,请检查它是否与正则表达式匹配整数在这里是理想的。

2:可以使用 boost::lexical_cast ,然后捕获一个潜在的 boost::bad_lexical_cast 异常,看看转换是否失败。如果您可以使用 boost 并且转换失败是一种特殊情况,这将很有效。

3:滚动您自己的类似于 lexical_cast 的函数,该函数检查转换并根据转换是否成功返回真/假。如果 1 和 2 不符合您的要求,这将起作用。

于 2010-05-16T18:06:08.757 回答
4

您可以boost::lexical_cast按照建议使用 ,但是如果您对字符串有任何先验知识(即,如果字符串包含整数文字,它将没有任何前导空格,或者整数永远不会用指数写入),然后滚动您自己的功能应该更有效,而且不是特别困难。

于 2010-05-16T18:11:47.487 回答
3

这是另一个解决方案。

try
{
  (void) std::stoi(myString); //cast to void to ignore the return value   
  //Success! myString contained an integer
} 
catch (const std::logic_error &e)
{   
  //Failure! myString did not contain an integer
}
于 2017-07-10T11:09:45.683 回答
3

从 C++11 开始,您可以使用std::all_of::isdigit

#include <algorithm>
#include <cctype>
#include <iostream>
#include <string_view>

int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
{
    auto isInt = [](std::string_view str) -> bool {
        return std::all_of(str.cbegin(), str.cend(), ::isdigit);
    };

    for(auto &test : {"abc", "123abc", "123.0", "+123", "-123", "123"}) {
        std::cout << "Is '" << test << "' numeric? " 
            << (isInt(test) ? "true" : "false") << std::endl;
    }

    return 0;
}

使用Godbolt查看结果。

于 2020-04-22T13:45:16.597 回答
2
template <typename T>
const T to(const string& sval)
{
        T val;
        stringstream ss;
        ss << sval;
        ss >> val;
        if(ss.fail())
                throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
        return val;
}

然后你可以像这样使用它:

double d = to<double>("4.3");

或者

int i = to<int>("4123");
于 2010-05-16T18:14:37.827 回答
2

我修改了 paercebal 的方法以满足我的需要:

typedef std::string String;    

bool isInt(const String& s, int base){
   if(s.empty() || std::isspace(s[0])) return false ;
   char * p ;
   strtol(s.c_str(), &p, base) ;
   return (*p == 0) ;
}


bool isPositiveInt(const String& s, int base){
   if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
   char * p ;
   strtol(s.c_str(), &p, base) ;
   return (*p == 0) ;
}


bool isNegativeInt(const String& s, int base){
   if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
   char * p ;
   strtol(s.c_str(), &p, base) ;
   return (*p == 0) ;
}

笔记:

  1. 您可以检查各种基础(二进制、八进制、十六进制等)
  2. 确保没有将1、 负值或值>36作为基数。
  3. 如果您0作为基数传递,它将自动检测基数,即以开头的字符串0x将被视为十六进制,以开头的字符串0将被视为八进制。字符不区分大小写。
  4. 字符串中的任何空格都会使其返回 false。
于 2015-11-24T12:22:38.137 回答