簡體   English   中英

如何使用boost lexical_cast庫來檢查輸入

[英]How to use the boost lexical_cast library for just for checking input

我使用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庫來執行輸入檢查?

你現在可以使用boost::conversion::try_lexical_convert boost/lexical_cast/try_lexical_convert.hpp標題中定義的boost::conversion::try_lexical_convert 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);

由於強制轉換可能拋出異常,因此只會丟棄該強制轉換的編譯器會嚴重破壞。 您可以假設所有主要編譯器都能正確處理此問題。

從性能的角度來看,嘗試執行lexical_cast可能並不是最優的,但除非您以這種方式檢查數百萬個值,否則無需擔心。

我想你想稍微重寫一下這個函數:

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

    return true; 
} 

你可以嘗試這樣的事情。

#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基本相同,除了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;
}

無論如何,編譯器都不太可能設法拋棄轉換。 例外只是錦上添花。 如果要優化它,則必須編寫自己的解析器來識別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)

最好先使用正則表達式,然后使用lexical_cast轉換為實際類型。

由於類型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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM