[英]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::string
, wstring
等。
例如,您可以添加以下代碼:
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.