简体   繁体   English

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

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

I use the boost lexical_cast library for parsing text data into numeric values quite often. 我使用boost lexical_cast库来经常将文本数据解析为数值。 In several situations however, I only need to check if values are numeric; 但是在几种情况下,我只需要检查值是否为数字; I don't actually need or use the conversion. 我实际上并不需要或使用转换。

So, I was thinking about writing a simple function to test if a string is a double: 所以,我正在考虑编写一个简单的函数来测试字符串是否为double:

template<typename T> 
bool is_double(const T& s)
{
  try 
  {
    boost::lexical_cast<double>(s); 
    return true;
  }
  catch (...) 
  {
    return false;
  }
}

My question is, are there any optimizing compilers that would drop out the lexical_cast here since I never actually use the value? 我的问题是,是否有任何优化编译器会在这里删除lexical_cast,因为我从未实际使用过该值?

Is there a better technique to use the lexical_cast library to perform input checking? 有没有更好的技术来使用lexical_cast库来执行输入检查?

You can now use boost::conversion::try_lexical_convert now defined in the header boost/lexical_cast/try_lexical_convert.hpp (if you only want try_lexical_convert ). 你现在可以使用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 )。 Like so: 像这样:

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

Since the cast might throw an an exception, a compiler that would just drop that cast would be seriously broken. 由于强制转换可能抛出异常,因此只会丢弃该强制转换的编译器会严重破坏。 You can assume that all major compilers will handle this correctly. 您可以假设所有主要编译器都能正确处理此问题。

Trying to to do the lexical_cast might not be optimal from a performance point of view, but unless you check millions of values this way it won't be anything to worry about. 从性能的角度来看,尝试执行lexical_cast可能并不是最优的,但除非您以这种方式检查数百万个值,否则无需担心。

I think you want to re-write that function slightly: 我想你想稍微重写一下这个函数:

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

    return true; 
} 

You could try something like this. 你可以尝试这样的事情。

#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) );
} 

The convert function does basically the same things as boost::lexical_cast, except lexical cast is more careful about avoiding allocating dynamic storage by using fixed buffers etc. convert函数与boost :: lexical_cast基本相同,除了lexical cast更加小心避免使用固定缓冲区等来分配动态存储。

It would be possible to refactor the boost::lexical_cast code into this form, but that code is pretty dense and tough going - IMHO its a pity that lexical_cast wasn't implemented using somethign like this under the hood... then it could look like this: 有可能将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;
}

The compiler is pretty unlikely to manage to throw out the conversion no matter what. 无论如何,编译器都不太可能设法抛弃转换。 Exceptions are just the icing on the cake. 例外只是锦上添花。 If you want to optimize this, you'll have to write your own parser to recognize the format for a float. 如果要优化它,则必须编写自己的解析器来识别float的格式。 Use regexps or manually parse, since the pattern is simple: 使用正则表达式或手动解析,因为模式很简单:

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();

Not tested… I'll let you run through all the possible format combinations ;v) 未经测试......我将让您浏览所有可能的格式组合; v)

Edit: Also, note that this is totally incompatible with localization. 编辑:另外,请注意,这与本地化完全不兼容。 You have absolutely no hope of internationally checking without converting. 没有转换,你绝对没有国际检查的希望。

Edit 2: Oops, I thought someone else already suggested this. 编辑2:哎呀,我以为别人已经建议了这个。 boost::lexical_cast is actually deceptively simple. boost::lexical_cast实际上看似简单。 To at least avoid throwing+catching the exception, you can reimplement it somewhat: 为了至少避免抛出+捕获异常,你可以稍微重新实现它:

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

This code, on the other hand, has been tested ;v) 另一方面,该代码已经过测试; v)

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

As the type T is a templated typename, I believe your answer is the right one, as it will be able to handle all cases already handled by boost::lexical_cast. 由于类型T是模板化的类型名称,我相信你的答案是正确的,因为它将能够处理已经由boost :: lexical_cast处理的所有情况。

Still, don't forget to specialize the function for known types, like char * , wchar_t * , std::string , wstring , etc. 不过,不要忘记专门针对已知类型的函数,如char *wchar_t *std::stringwstring等。

For example, you could add the following code : 例如,您可以添加以下代码:

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) ;
}

This way, you can "optimize" the processing for the types you know, and delegate the remaining cases to boost::lexical_cast. 这样,您可以“优化”您所知类型的处理,并将剩余的案例委托给boost :: lexical_cast。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM