如何使用boost lexical_cast库来检查输入

时间:2010-02-12 04:43:04

标签: c++ boost lexical-cast

我使用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库来执行输入检查?

7 个答案:

答案 0 :(得分:3)

现在,您可以使用标头boost/lexical_cast/try_lexical_convert.hpp中现在定义的boost::conversion::try_lexical_convert(如果您只想要try_lexical_convert)。像这样:

double temp;
std::string convert{"abcdef"};
assert(boost::conversion::try_lexical_convert<double>(convert, temp) != false);

答案 1 :(得分:2)

由于强制转换可能会抛出异常,因此只会丢弃该强制转换的编译器会严重破坏。您可以假设所有主要编译器都能正确处理。

从性能的角度来看,尝试执行lexical_cast可能并不是最优的,但除非你以这种方式检查数百万个值,否则不必担心。

答案 2 :(得分:2)

我想你想稍微重写一下这个功能:

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

    return true; 
} 

答案 3 :(得分: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基本相同,除了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;
}

答案 4 :(得分: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)

答案 5 :(得分:0)

最好先使用正则表达式,然后使用lexical_cast转换为实际类型。

答案 6 :(得分: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。