3 Stimmen

Verwendung der boost lexical_cast-Bibliothek nur zur Überprüfung der Eingabe

Ich benutze die boost lexical_cast Bibliothek für das Parsen von Textdaten in numerische Werte ziemlich oft. In einigen Situationen muss ich jedoch nur prüfen, ob die Werte numerisch sind; ich brauche oder verwende die Konvertierung eigentlich nicht.

Also, ich war über das Schreiben einer einfachen Funktion zu testen, ob eine Zeichenfolge ein Doppel ist denken:

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

Meine Frage ist, gibt es alle optimierenden Compiler, die die lexical_cast hier weglassen würde, da ich nie tatsächlich den Wert verwenden?

Gibt es eine bessere Technik, um die lexical_cast-Bibliothek zu verwenden, um die Eingabeprüfung durchzuführen?

7voto

miguel.martin Punkte 1586

Sie können nun Folgendes verwenden boost::conversion::try_lexical_convert jetzt in der Kopfzeile definiert boost/lexical_cast/try_lexical_convert.hpp (wenn Sie nur try_lexical_convert ). Etwa so:

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

2voto

sth Punkte 210180

Da der Cast eine Ausnahme auslösen könnte, wäre ein Compiler, der diesen Cast einfach weglassen würde, ernsthaft defekt. Sie können davon ausgehen, dass alle gängigen Compiler dies korrekt handhaben.

Der Versuch, die lexical_cast zu tun könnte nicht optimal aus der Sicht der Leistung sein, aber wenn Sie Millionen von Werten auf diese Weise überprüfen, wird es nichts zu befürchten sein.

2voto

Martin York Punkte 245363

Ich glaube, Sie sollten diese Funktion etwas umschreiben:

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

    return true; 
}

1voto

Michael Anderson Punkte 65535

Sie könnten es so versuchen.

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

Die Funktion convert tut im Grunde dasselbe wie boost::lexical_cast, nur dass lexical cast darauf achtet, die Zuweisung von dynamischem Speicher durch die Verwendung fester Puffer usw. zu vermeiden.

Es wäre möglich, den boost::lexical_cast-Code in diese Form zu refaktorieren, aber dieser Code ist ziemlich dicht und zählebig - IMHO ist es schade, dass lexical_cast nicht mit etwas wie diesem unter der Haube implementiert wurde... dann könnte es so aussehen:

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

0voto

Potatoswatter Punkte 130562

Es ist ziemlich unwahrscheinlich, dass der Compiler es schafft, die Umwandlung zu verwerfen, egal was passiert. Ausnahmen sind nur das Sahnehäubchen auf dem Kuchen. Wenn Sie dies optimieren wollen, müssen Sie einen eigenen Parser schreiben, um das Format für einen Float zu erkennen. Verwenden Sie Regexps oder parsen Sie manuell, da das Muster einfach ist:

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

Nicht getestet Ich lasse Sie alle möglichen Formatkombinationen durchspielen ;v)

Edit: Beachten Sie auch, dass dies völlig unvereinbar mit der Lokalisierung ist. Sie haben absolut keine Hoffnung auf eine internationale Prüfung ohne Konvertierung.

Edit 2: Ups, ich dachte, das hätte schon jemand anderes vorgeschlagen. boost::lexical_cast ist eigentlich täuschend einfach. Um zumindest zu vermeiden, dass die Ausnahme geworfen und aufgefangen wird, können Sie sie etwas umgestalten:

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

Dieser Code hingegen wurde getestet ;v)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X