22

std::string文字列または値(など)の可能性があるaがあります0

失敗する機能を備えたstd::stringに変換するための最良または最も簡単な方法は何ですか?intC#のC++バージョンが必要ですInt32.TryParse

4

5 に答える 5

43

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

ブーストなし:

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

偽のブースト:

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

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;
    }   
}
于 2009-08-07T07:31:28.787 に答える
9

ストリームを使用する他の回答は、文字列に有効な数字の後に無効な文字が含まれている場合でも成功します(例: "123abc")。私はブーストに精通していないので、その動作についてコメントすることはできません。

文字列に数字が含まれていて、数字のみが含まれているかどうかを知りたい場合は、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は、解析を終了した文字へのポインタを返すため、文字列全体が解析されたかどうかを簡単に確認できます。

strtolはintではなくlongを返すことに注意してください。ただし、コンパイラによっては、これらはおそらく同じです。標準ライブラリにはstrtoi関数はなく、解析終了文字を返さないatoiのみがあります。

于 2009-08-07T08:10:07.147 に答える
9

ブールテストには例外を使用しないでください

受け入れられた回答は、「例外的な場合に例外を使用する」という原則に違反しているため、質問に対するひどい回答です。

例外は、例外的なケース(何かが本当にうまくいかなかった場合)を処理するための優れたツールです。これらは、既存のユースケースには不十分なツールです。例外をスローしてキャッチするのはコストがかかることと、誤解を招くコードであることが理由の1つです。開発者が例外を見つけた場合、そこで何かがうまくいかないと合理的に想定できるはずです。この基本原則についての良い議論はたくさんありますが、私は「実用的なプログラマー」が好きです、またはこれは悪くありません:http ://www.lohmy.de/2013/03/06/writing-use-cases-exception-または-alternate-flow/

常に数値が予想される場合は、boost::lexical_castを使用してください

boost :: lexical_castは、数値以外を受信することが実際には例外である場合に最適なソリューションです。

非数値がユースケースの一部である場合は、boost::try_lexical_convertを使用します

文字列を調べていて、それが数値の場合は1つのことを実行し、数値の場合は別のことを実行したい場合は、ブールテストの例外を使用しないでください。それは悪いプログラミングです。

実際、boostは、lexical_castの実装で使用されるtry_lexical_convertを提供します(ここのドキュメントから取得: 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;
}
于 2015-10-09T12:16:58.737 に答える
8

標準ストリームを使用する別の方法:

#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!";
    }
}
于 2009-08-07T07:34:36.657 に答える
3

ブースト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);
}
于 2009-08-07T09:10:25.950 に答える