[英]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.