繁体   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