Problem
You have a string and you need to find out if it contains a valid number.
Solution
You can use the Boost lexical_cast function template to test for a valid number. Using this approach, a valid number can include a preceding minus sign, or a preceding plus sign, but not whitespace. I give a few examples of the kinds of formats that work with lexical_cast in Example 3-5.
Example 3-5. Validating a string number
#include #include using namespace std; using boost::lexical_cast; using boost::bad_lexical_cast; template bool isValid(const string& num) { bool res = true; try { T tmp = lexical_cast(num); } catch (bad_lexical_cast &e) { res = false; } return(res); } void test(const string& s) { if (isValid(s)) cout << s << " is a valid integer." << endl; else cout << s << " is NOT a valid integer." << endl; if (isValid(s)) cout << s << " is a valid double." << endl; else cout << s << " is NOT a valid double." << endl; if (isValid(s)) cout << s << " is a valid float." << endl; else cout << s << " is NOT a valid float." << endl; } int main( ) { test("12345"); test("1.23456"); test("-1.23456"); test(" - 1.23456"); test("+1.23456"); test(" 1.23456 "); test("asdf"); }
Here's the output from this example:
12345 is a valid integer. 12345 is a valid double. 12345 is a valid float. 1.23456 is NOT a valid integer. 1.23456 is a valid double. 1.23456 is a valid float. -1.23456 is NOT a valid integer. -1.23456 is a valid double. -1.23456 is a valid float. - 1.23456 is NOT a valid integer. - 1.23456 is NOT a valid double. - 1.23456 is NOT a valid float. +1.23456 is NOT a valid integer. +1.23456 is a valid double. +1.23456 is a valid float. 1.23456 is NOT a valid integer. 1.23456 is NOT a valid double. 1.23456 is NOT a valid float. asdf is NOT a valid integer. asdf is NOT a valid double. asdf is NOT a valid float.
Discussion
The lexical_cast function template converts a value from one type to another. It is declared like this:
template Target lexical_cast(Source arg)
Source is the type of the original variable, and Target is the type of the variable being converted to. So, for example, if you want to convert from a string to an int, you invoke lexical_cast like this:
int i = lexical_cast(str); // str is a string
lexical_cast does the parsing and attempts the conversion. If the conversion is not possible, it throws a bad_lexical_cast exception. In Example 3-5, I only want to test for validity and don't need to keep the destination variable around, so I return true if no exception is thrown, false otherwise.
You only have to supply the first template argument to lexical_cast because it's a function template, which means the compiler can deduce the type of the function argument and use that as the second template argument. Explaining this distinction is more confusing than illustrating it, so let me use a code example. Instead of invoking lexical_cast as in the previous code snippet, you could do this:
int i = lexical_cast(str);
This means the same thing, but you don't have to supply the string argument because the compiler can see that str is a string and figure out the rest.
If you are going to write a similar wrapper function to test for validity and return true or false, you would do well to write it as a function template. This way, you only have to write it once with a parameterized type, and a different version will be instantiated each time you use it on a different type.
lexical_cast is also handy for converting from one numeric type to another; I discuss more about that in Recipe Recipe 3.6.
See Also
Recipe 3.6
Building C++ Applications
Code Organization
Numbers
Strings and Text
Dates and Times
Managing Data with Containers
Algorithms
Classes
Exceptions and Safety
Streams and Files
Science and Mathematics
Multithreading
Internationalization
XML
Miscellaneous
Index