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

时间:2022-03-03 02:57:31

I have a std::string which could be a string or could be a value (such as 0).

我有一个std :: string,它可以是一个字符串,也可以是一个值(例如0)。

What is the best or easiest way to convert the std::string to int with the ability to fail? I want a C++ version of C#'s Int32.TryParse.

将std :: string转换为int的最佳或最简单的方法是什么?我想要一个C ++版本的C#的Int32.TryParse。

5 个解决方案

#1


42  

Use boost::lexical_cast. If the cast cannot be done, it will throw an exception.

使用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(...)
    {
        /* ... */
    }
}

Without boost:

#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(...)
    {
        /* ... */
    }
}

Faking boost:

#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(...)
    {
        /* ... */
    }
}

If you want no-throw versions of these functions, you'll have to catch the appropriate exceptions (I don't think boost::lexical_cast provides a no-throw version), something like this:

如果你想要这些函数的无抛出版本,你必须捕获相应的异常(我不认为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;
    }   
}

#2


8  

The other answers that use streams will succeed even if the string contains invalid characters after a valid number e.g. "123abc". I'm not familiar with boost, so can't comment on its behavior.

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

If you want to know if the string contains a number and only a number, you have to use strtol:

如果您想知道字符串是否包含数字而只包含数字,则必须使用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
    }
}

strtol returns a pointer to the character that ended the parse, so you can easily check if the entire string was parsed.

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

Note that strtol returns a long not an int, but depending on your compiler these are probably the same. There is no strtoi function in the standard library, only atoi, which doesn't return the parse ending character.

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

#3


7  

Another way using standard streams :

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

#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!";
    }
}

#4


6  

Exceptions should not be used for boolean tests

The accepted answer is really a terrible answer for question as asked, as it violates the precept "use exceptions for exceptional cases".

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

Exceptions are an excellent tool for handling exceptional cases -- cases where something has genuinely gone wrong. They are poor tools for existing use-cases. Partly because throwing and catching an exception is expensive, and partly because it is misleading code -- when a developer sees an exception they should reasonably be able to assume something is going wrong there. Good discussions of this basic principle abound, but I like "The Pragmatic Programmer"'s, or this isn't bad: http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/

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

Use boost::lexical_cast if you always expect a number

boost::lexical_cast is an optimal solution when it really is an exception for it to be receiving a non-number.

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

Use boost::try_lexical_convert if non-numbers are part of your use case

If you are going through a string and want to do one thing if it's a number, and another if it's a number, don't use an exception for the boolean test. That's just bad programming.

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

In fact, boost offers try_lexical_convert, which is used in the implementation of lexical_cast (taken from the documentation here: http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast).

实际上,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;
}

#5


2  

Before boost's lexical_cast was available, I used to do the following:

在boost的lexical_cast可用之前,我曾经做过以下事情:

namespace detail {

    template< typename Target, typename Source >
    struct stream_caster {
        static Target stream_cast(const Source& s)
        {
            std::stringstream ss;
            if( (ss << s).fail() ) {
                throw std::bad_cast("could not stream from source");
            }
            Target t;
            if( (ss >> t).fail() || !(ss >> ws).eof) {
                throw std::bad_cast("could not stream to target");
            }
            return t;
        }
    };

    template< typename T >
    struct stream_caster<T,T> {
        static const T& stream_cast(const T& s)
        {
            return s;
        }
    };

    template< typename Source >
    struct stream_caster<std::string,Source> {
        static std::string stream_cast(const Source& s)
        {
            std::ostringstream oss;
            if( (oss << s).fail() ) {
                throw std::bad_cast("could not stream from source");
            }
            return oss.str();
        }
    };

    template< typename Target >
    struct stream_caster<Target,std::string> {
        static Target stream_cast(const std::string& s)
        {
            std::stringstream ss(s);
            Target t;
            if( (ss >> t).fail() || !(ss >> ws).eof) {
                throw std::bad_cast("could not stream to target");
            }
            return t;
        }
    };

    template<>
    struct stream_caster<std::string,std::string> {
        static const std::string& stream_cast(const std::string& s)
        {
            return s;
        }
    };

}

template< typename Target, typename Source >
inline Target stream_cast(const Source& s)
{
    return detail::stream_caster<Target,Source>::stream_cast(s);
}

#1


42  

Use boost::lexical_cast. If the cast cannot be done, it will throw an exception.

使用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(...)
    {
        /* ... */
    }
}

Without boost:

#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(...)
    {
        /* ... */
    }
}

Faking boost:

#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(...)
    {
        /* ... */
    }
}

If you want no-throw versions of these functions, you'll have to catch the appropriate exceptions (I don't think boost::lexical_cast provides a no-throw version), something like this:

如果你想要这些函数的无抛出版本,你必须捕获相应的异常(我不认为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;
    }   
}

#2


8  

The other answers that use streams will succeed even if the string contains invalid characters after a valid number e.g. "123abc". I'm not familiar with boost, so can't comment on its behavior.

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

If you want to know if the string contains a number and only a number, you have to use strtol:

如果您想知道字符串是否包含数字而只包含数字,则必须使用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
    }
}

strtol returns a pointer to the character that ended the parse, so you can easily check if the entire string was parsed.

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

Note that strtol returns a long not an int, but depending on your compiler these are probably the same. There is no strtoi function in the standard library, only atoi, which doesn't return the parse ending character.

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

#3


7  

Another way using standard streams :

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

#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!";
    }
}

#4


6  

Exceptions should not be used for boolean tests

The accepted answer is really a terrible answer for question as asked, as it violates the precept "use exceptions for exceptional cases".

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

Exceptions are an excellent tool for handling exceptional cases -- cases where something has genuinely gone wrong. They are poor tools for existing use-cases. Partly because throwing and catching an exception is expensive, and partly because it is misleading code -- when a developer sees an exception they should reasonably be able to assume something is going wrong there. Good discussions of this basic principle abound, but I like "The Pragmatic Programmer"'s, or this isn't bad: http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/

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

Use boost::lexical_cast if you always expect a number

boost::lexical_cast is an optimal solution when it really is an exception for it to be receiving a non-number.

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

Use boost::try_lexical_convert if non-numbers are part of your use case

If you are going through a string and want to do one thing if it's a number, and another if it's a number, don't use an exception for the boolean test. That's just bad programming.

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

In fact, boost offers try_lexical_convert, which is used in the implementation of lexical_cast (taken from the documentation here: http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast).

实际上,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;
}

#5


2  

Before boost's lexical_cast was available, I used to do the following:

在boost的lexical_cast可用之前,我曾经做过以下事情:

namespace detail {

    template< typename Target, typename Source >
    struct stream_caster {
        static Target stream_cast(const Source& s)
        {
            std::stringstream ss;
            if( (ss << s).fail() ) {
                throw std::bad_cast("could not stream from source");
            }
            Target t;
            if( (ss >> t).fail() || !(ss >> ws).eof) {
                throw std::bad_cast("could not stream to target");
            }
            return t;
        }
    };

    template< typename T >
    struct stream_caster<T,T> {
        static const T& stream_cast(const T& s)
        {
            return s;
        }
    };

    template< typename Source >
    struct stream_caster<std::string,Source> {
        static std::string stream_cast(const Source& s)
        {
            std::ostringstream oss;
            if( (oss << s).fail() ) {
                throw std::bad_cast("could not stream from source");
            }
            return oss.str();
        }
    };

    template< typename Target >
    struct stream_caster<Target,std::string> {
        static Target stream_cast(const std::string& s)
        {
            std::stringstream ss(s);
            Target t;
            if( (ss >> t).fail() || !(ss >> ws).eof) {
                throw std::bad_cast("could not stream to target");
            }
            return t;
        }
    };

    template<>
    struct stream_caster<std::string,std::string> {
        static const std::string& stream_cast(const std::string& s)
        {
            return s;
        }
    };

}

template< typename Target, typename Source >
inline Target stream_cast(const Source& s)
{
    return detail::stream_caster<Target,Source>::stream_cast(s);
}