如何检查 std::string 是否为整数?

5
以下代码将一个 std::string 转换为 int,问题在于它无法区分真正的整数和随机字符串。有没有一种系统的方法来处理这样的问题?
#include <cstring>
#include <iostream>
#include <sstream>

int main()
{
    std::string str =  "H";

    int int_value;
    std::istringstream ss(str);
    ss >> int_value;

    std::cout<<int_value<<std::endl;

    return 0;
}

编辑:这是我喜欢的解决方案,因为它非常简洁优雅!它不能处理负数,但我只需要正数。

#include <cstring>
#include <iostream>
#include <sstream>

int main()
{
    std::string str =  "2147483647";

    int int_value;
    std::istringstream ss(str);

    if (ss >> int_value)
        std::cout << "Hooray!" << std::endl;

    std::cout<<int_value<<std::endl;


    str =  "-2147483648";
    std::istringstream negative_ss(str);

    if (ss >> int_value)
        std::cout << "Hooray!" << std::endl;

    std::cout<<int_value<<std::endl;

    return 0;
}

3
if (ss >> int_value) 可能是一个不错的开始。 - WhozCraig
1
试一下。将您当前的裸 ss >> int_value; 替换为 if (ss >> int_value) std::cout << "Hooray!" << std::endl; - WhozCraig
WhozCraig建议中使用的string stream operator的一些信息。 - Captain Obvlious
请注意,如果存在前导空格,则它将跳过以达到所需的对象,因此 "10""-100"" -42" 都可以使用。如果这是您想要的方法,那么它是一个非常强大的机制。如果您希望除了纯数值(包括可选符号)外,任何其他内容都失败,甚至在前导空格上也会失败,那么它就不适合,或者至少需要一些准备工作。 - WhozCraig
1
嗯,听起来很熟悉,你可能想看一下http://stackoverflow.com/questions/16156881/checking-to-make-sure-argv1-is-an-integer-c这个链接,还有我的解决方案http://stackoverflow.com/questions/16156881/checking-to-make-sure-argv1-is-an-integer-c/16156999#16156999。 - Arun
显示剩余3条评论
3个回答

7
您可以尝试使用Boost的lexical_cast,如果转换失败,它将抛出一个异常。
int number;
try
{
     number = boost::lexical_cast<int>(str);
}
catch(boost::bad_lexical_cast& e)
{
    std::cout << str << "isn't an integer number" << std::endl;
}

编辑 根据@chris的说法,你也可以尝试使用C++11中的std::stoi。如果无法进行转换,它将抛出std::invalid_argument异常。您可以在此处找到更多信息:std::stoi


谢谢你的回复,TACP,但是WhozCraig用非常简单的方式回答了它。不过还是谢谢。 - pandoragami
@WhozCraig 是的,第一种方法会忽略负数,非常感谢你发现了这个问题。我已经更新了它来指出这一点。 - taocp
@lost_with_coding 欢迎你,但正如WhozCraig指出的那样,当字符串实际上是负数时,第一种方法将不起作用。因此最好使用boost lexical_cast方法。 - taocp
@tacp 是的,我才注意到这一点,因为我已经不知道自己犯了多少次同样的错误了。(叹气) - WhozCraig
1
这个概念是正确的。对我来说,循环看起来不像符合C++惯用法。 - Arun
1
顺便说一下,在标准库中有一个类似的函数,std::stoi,但它稍微不那么严格,并且会抛出两到三个不同的异常。 - chris

5

WhozCraig的方法更好,我想扩展一下它,使用C++ FAQ所使用的方法,具体如下:

#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept>

class BadConversion : public std::runtime_error {
public:
  BadConversion(std::string const& s)
    : std::runtime_error(s)
    { }
};



inline int convertToInt(std::string const& s,
                              bool failIfLeftoverChars = true)
{
  std::istringstream i(s);
  int x;
  char c;
  if (!(i >> x) || (failIfLeftoverChars && i.get(c)))
    throw BadConversion("convertToInt(\"" + s + "\")");
  return x;
}


int main()
{
    std::cout << convertToInt( "100" ) << std::endl ;
    std::cout << convertToInt( "-100" ) << std::endl ;
    std::cout << convertToInt( "  -100" ) << std::endl ;
    std::cout << convertToInt( "  -100  ", false ) << std::endl ;

    // The next two will fail
    std::cout << convertToInt( "  -100  ", true ) << std::endl ;
    std::cout << convertToInt( "H" ) << std::endl ;
}

这是一个强大的工具,它能够判断转换是否失败,您也可以选择在有剩余字符时自动失败。

我想我曾经做过类似的东西,虽然更通用,并且提供了 std::stoiboost::lexical_cast 没有的一些特定功能。它是这样的:if (SafeInput::Input("请输入整数: ", someInt, SafeInput::Options::NoLeftovers)) {...} :p - chris

1
/* isdigit example */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main ()
{
  char str[]="1776ad";
  int year;
  if (isdigit(str[0]))
  {
    year = atoi (str);
    printf ("The year that followed %d was %d.\n",year,year+1);
  }
  return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接