3

テキスト データを数値に解析するために、boost lexical_cast ライブラリを頻繁に使用します。ただし、いくつかの状況では、値が数値かどうかのみを確認する必要があります。私は実際には変換を必要としないか、使用しません。

そこで、文字列が double かどうかをテストする単純な関数を作成することを考えていました。

template<typename T> 
bool is_double(const T& s)
{
  try 
  {
    boost::lexical_cast<double>(s); 
    return true;
  }
  catch (...) 
  {
    return false;
  }
}

私の質問は、実際に値を使用したことがないため、ここで lexical_cast を削除する最適化コンパイラはありますか?

lexical_cast ライブラリを使用して入力チェックを実行するためのより良い手法はありますか?

4

7 に答える 7

6

boost::conversion::try_lexical_convertヘッダーで定義されたnow を使用できるようになりましたboost/lexical_cast/try_lexical_convert.hpp(必要な場合のみtry_lexical_convert)。そのようです:

double temp;
std::string convert{"abcdef"};
assert(boost::conversion::try_lexical_convert<double>(convert, temp) != false);
于 2015-05-13T13:10:06.107 に答える
2

その関数を少し書き直したいと思います:

template<typename T>  
bool tryConvert(std::string const& s) 
{ 
    try         { boost::lexical_cast<T>(s);} 
    catch (...) { return false; }

    return true; 
} 
于 2010-02-12T05:09:21.980 に答える
2

キャストは例外をスローする可能性があるため、そのキャストをドロップするだけのコンパイラーは深刻に壊れます。すべての主要なコンパイラがこれを正しく処理すると想定できます。

lexical_cast を実行しようとすることは、パフォーマンスの観点からは最適ではないかもしれませんが、この方法で何百万もの値をチェックしない限り、心配する必要はありません。

于 2010-02-12T05:07:13.647 に答える
1

このようなことを試すことができます。

#include <sstream>

//Try to convert arg to result in a similar way to boost::lexical_cast
//but return true/false rather than throwing an exception.
template<typename T1, typename T2>
bool convert( const T1 & arg, T2 & result )
{
    std::stringstream interpreter;
    return interpreter<<arg && 
           interpreter>>result && 
           interpreter.get() == std::stringstream::traits_type::eof();
}

template<typename T>
double to_double( const T & t )
{
   double retval=0;
   if( ! convert(t,retval) ) { /* Do something about failure */ }
   return retval;
}

template<typename T>
double is_double( const T & t )
{
   double retval=0;
   return convert(t,retval) );
} 

convert 関数は基本的に boost::lexical_cast と同じことを行いますが、レキシカル キャストは固定バッファなどを使用して動的ストレージの割り当てを避けることに注意を払っています。

boost::lexical_cast コードをこの形式にリファクタリングすることは可能ですが、そのコードはかなり高密度で難しいものです - 私見では、内部でこのようなものを使用して lexical_cast が実装されていないのは残念です...その後、それは見えるかもしれませんこのような:

template<typename T1, typename T2>
T1 lexical_cast( const T2 & t )
{
  T1 retval;
  if( ! try_cast<T1,T2>(t,retval) ) throw bad_lexical_cast();
  return retval;
}
于 2010-02-12T06:11:44.073 に答える
0

コンパイラが何があっても変換を破棄することはほとんどありません。例外は、ケーキの上のアイシングです。これを最適化する場合は、floatの形式を認識するために独自のパーサーを作成する必要があります。パターンは単純なので、正規表現を使用するか、手動で解析します。

if ( s.empty() ) return false;
string::const_iterator si = s.begin();
if ( *si == '+' || * si == '-' ) ++ si;
if ( si == s.end() ) return false;
while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
if ( si == s.end() ) return true;
if ( * si == '.' ) ++ si;
if ( ( * si == 'e' || * si == 'E' )
 && si - s.begin() <= 1 + (s[0] == '+') + (s[0] == '-') ) return false;
if ( si == s.end() ) return si - s.begin() > 1 + (s[0] == '+') + (s[0] == '-');
while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
if ( si == s.end() ) return true;
if ( * si == 'e' || * si == 'E' ) {
    ++ si;
    if ( si == s.end() ) return false;
    if ( * si == '-' || * si == '+' ) ++ si;
    if ( si == s.end() ) return false;
    while ( '0' <= *si && *si <= '9' && si != s.end() ) ++ si;
}
return si == s.end();

テストされていません…可能なすべてのフォーマットの組み合わせを実行させます;v)

編集:また、これはローカリゼーションと完全に互換性がないことに注意してください。改宗せずに国際的にチェックする望みはまったくありません。

編集2:おっと、私は他の誰かがすでにこれを提案していると思いました。boost::lexical_cast実際には一見シンプルです。少なくとも例外のスローとキャッチを回避するために、例外をいくらか再実装できます。

istringstream ss( s );
double d;
ss >> d >> ws; // ws discards whitespace
return ss && ss.eof(); // omit ws and eof if you know no trailing spaces

一方、このコードはテスト済みです; v)

于 2010-02-12T05:29:56.287 に答える
0

最初に正規表現を使用し、実際の型に変換するためだけに lexical_cast を使用することをお勧めします。

于 2010-02-12T06:11:57.623 に答える
0

タイプ T はテンプレート化されたタイプ名であるため、boost::lexical_cast によってすでに処理されているすべてのケースを処理できるため、あなたの答えは正しいと思います。

char *それでも、wchar_t *std::stringwstring、 などの既知の型に関数を特化することを忘れないでください。

たとえば、次のコードを追加できます。

template<>
bool is_double<int>(const int & s)
{
   return true ;
}

template<>
bool is_double<double>(const double & s)
{
   return true ;
}

template<>
bool is_double<std::string>(const std::string & s)
{
   char * p ;
   strtod(s.c_str(), &p) ; // include <cstdlib> for strtod
   return (*p == 0) ;
}

このようにして、既知のタイプの処理を「最適化」し、残りのケースを boost::lexical_cast に委譲できます。

于 2010-02-12T09:49:05.000 に答える