在C++中使用bool/fail将字符串转换为int

20 c++ parsing c++-faq

我有一个std::string可能是一个字符串或可能是一个值(如0).

转换std::stringint具有失败能力的最佳或最简单的方法是什么?我想要C#的C++版本Int32.TryParse.

GMa*_*ckG 41

使用boost :: lexical_cast.如果无法完成强制转换,则会抛出异常.

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>

int main(void)
{
    std::string s;
    std::cin >> s;

    try
    {
        int i = boost::lexical_cast<int>(s);

        /* ... */
    }
    catch(...)
    {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

没有提升:

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

int main(void)
{
    std::string s;
    std::cin >> s;

    try
    {
        std::stringstream ss(s);

        int i;
        if ((ss >> i).fail() || !(ss >> std::ws).eof())
        {
            throw std::bad_cast();
        }

        /* ... */
    }
    catch(...)
    {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

假装提升:

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

template <typename T>
T lexical_cast(const std::string& s)
{
    std::stringstream ss(s);

    T result;
    if ((ss >> result).fail() || !(ss >> std::ws).eof())
    {
        throw std::bad_cast();
    }

    return result;
}

int main(void)
{
    std::string s;
    std::cin >> s;

    try
    {
        int i = lexical_cast<int>(s);

        /* ... */
    }
    catch(...)
    {
        /* ... */
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你想要这些函数的无抛出版本,你将必须捕获适当的异常(我不认为boost::lexical_cast提供无抛出版本),如下所示:

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

template <typename T>
T lexical_cast(const std::string& s)
{
    std::stringstream ss(s);

    T result;
    if ((ss >> result).fail() || !(ss >> std::ws).eof())
    {
        throw std::bad_cast();
    }

    return result;
}

template <typename T>
bool lexical_cast(const std::string& s, T& t)
{
    try
    {
        // code-reuse! you could wrap
        // boost::lexical_cast up like
        // this as well
        t = lexical_cast<T>(s);

        return true;
    }
    catch (const std::bad_cast& e)
    {
        return false;
    }
}

int main(void)
{
    std::string s;
    std::cin >> s;

    int i;
    if (!lexical_cast(s, i))
    {
        std::cout << "Bad cast." << std::endl;
    }   
}
Run Code Online (Sandbox Code Playgroud)


Phi*_*ney 9

即使字符串在有效数字后面包含无效字符,例如"123abc",使用流的其他答案也会成功.我不熟悉boost,所以无法评论它的行为.

如果您想知道字符串是否包含数字且只包含数字,则必须使用strtol:

#include <iostream>
#include <string>

int main(void)
{
    std::string s;
    std::cin >> s;

    char *end;
    long i = strtol( s.c_str(), &end, 10 );
    if ( *end == '\0' )
    {
        // Success
    }
    else
    {
        // Failure
    }
}
Run Code Online (Sandbox Code Playgroud)

strtol返回指向结束解析的字符的指针,因此您可以轻松检查是否已解析整个字符串.

请注意,strtol返回long而不是int,但根据您的编译器,这些可能是相同的.标准库中没有strtoi函数,只有atoi,它不返回解析结束字符.


Spa*_*ose 8

不应将异常用于布尔测试

对于问题,接受的答案确实是一个可怕的答案,因为它违反了"使用特殊情况例外"的规定.

例外是处理特殊情况的极好工具 - 事情确实出现了问题.它们是现有用例的糟糕工具.部分原因是抛出和捕获异常是昂贵的,部分是因为它是误导性的代码 - 当开发人员看到异常时,他们应该合理地能够假设某些东西出错了.对这个基本原则的良好讨论比比皆是,但我喜欢"实用程序员",或者这不错:http://www.lohmy.de/2013/03/06/writing-use-cases-exception-或-备用流/

如果你总是期望一个数字,请使用boost :: lexical_cast

boost :: lexical_cast是一个最佳的解决方案,当它真的是一个例外,它接收一个非数字.

如果非数字是您的用例的一部分,请使用boost :: try_lexical_convert

如果你正在浏览一个字符串并想要做一件事,如果它是一个数字,另一个如果它是一个数字,不要使用布尔测试的例外.那只是糟糕的编程.

实际上,boost提供了try_lexical_convert,它用于lexical_cast的实现(取自这里的文档:http: //www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast. synopsis.lexical_cast).

template <typename Target, typename Source>
    inline Target lexical_cast(const Source &arg)
{
    Target result;

    if (!conversion::try_lexical_convert(arg, result))
        throw bad_lexical_cast();

    return result;
}
Run Code Online (Sandbox Code Playgroud)


Ara*_*raK 7

使用标准流的另一种方法:

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

int main()
{
    std::stringstream convertor;
    std::string numberString = "Not a number!";
    int number;

    convertor << numberString;
    convertor >> number;

    if(convertor.fail())
    {
        // numberString is not a number!
        std::cout << "Not a Number!";
    }
}
Run Code Online (Sandbox Code Playgroud)