Home > Software engineering >  boost::lexical_cast can convert hex inside string to int?
boost::lexical_cast can convert hex inside string to int?

Time:11-04

I see in this topic C convert hex string to signed integer that boost::lexical_cast can convert hexadecimal inside string to another type (int, long...)

but when I tried this code:

std::string s = "0x3e8";

try {
    auto i = boost::lexical_cast<int>(s);
    std::cout << i << std::endl;        // 1000
}
catch (boost::bad_lexical_cast& e) {
    // bad input - handle exception
    std::cout << "bad" << std::endl;
}

It ends with a bad lexical cast exception !

boost doesn't support this kind of cast from string hex to int ?

CodePudding user response:

As per the answer from C convert hex string to signed integer:

It appears that since lexical_cast<> is defined to have stream conversion semantics. Sadly, streams don't understand the "0x" notation. So both the boost::lexical_cast and my hand rolled one don't deal well with hex strings.

Also, as per boost::lexical_cast<> documentation

The lexical_cast function template offers a convenient and consistent form for supporting common conversions to and from arbitrary types when they are represented as text. The simplification it offers is in expression-level convenience for such conversions. For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of lexical_cast, the conventional std::stringstream approach is recommended.

So for more involved conversion, std::stringstream is recommended.

If you have access to C 11 compiler, you can use std::stoi to convert any hexadecimal sting to an integer value.

stoi prototype is:

int stoi( const std::string& str, std::size_t* pos = nullptr, int base = 10 );

Your program can be converted to

int main() {
    std::string s = "3e8";
    auto i = std::stoi(s, nullptr, 16);
    std::cout << i << '\n';
}

And the output will be

1000

CodePudding user response:

What you want exists in Boost Convert:

Boost.Convert builds on the boost::lexical_cast experience and takes those type conversion/transformation-related ideas further

  • to be applicable to a wider range of conversion-related deployment scenarios,
  • to provide a more flexible, configurable and extendible type-conversion framework,
  • to provide generic consistent behavior,
  • to unify and to uniformly deploy various conversion facilities through one consistent interface.

Simple Usage

You can e.g. use stream conversion:

boost::cnv::cstream converter;

You can configure it with the manipulators you want, e.g.:

converter(std::hex)(std::skipws);  // IO manipulators

You could use directly:

boost::optional<int> i;
converter(s, i);
std::cout << i << std::endl; // 1000

But I'd suggest applying with pre-configured error-handling:

auto f = apply<int>(std::ref(converter))
     .value_or(-1); // decorate error-handling

Now you can simply write:

for (auto s : cases)
    std::cout << f(s) << std::endl;

Live Demo

Live On Coliru

#include <boost/convert.hpp>
#include <boost/convert/stream.hpp>
#include <iostream>

static const std::string cases[]{
    "0x3e8", "3e8", "-7a", "-0x7a",
    "0x-7a", // error
};

int main() {
    boost::cnv::cstream converter;
    converter(std::hex)(std::skipws);                      // IO manipulators
    auto f = apply<int>(std::ref(converter)).value_or(-1); // decorate error-handling

    for (auto s : cases)
        std::cout << std::quoted(s) << " -> " << f(s) << std::endl;

    auto g = apply<int>(std::ref(converter)); // throwing
    for (auto s : cases)
        try {
            std::cout << std::quoted(s) << " -> " << g(s) << std::endl;
        } catch (std::exception const& e) {
            std::cout << e.what() << std::endl;
        }
}

Prints

"0x3e8" -> 1000
"3e8" -> 1000
"-7a" -> -122
"-0x7a" -> -122
"0x-7a" -> -1
"0x3e8" -> 1000
"3e8" -> 1000
"-7a" -> -122
"-0x7a" -> -122
"0x-7a" -> Attempted to access the value of an uninitialized optional object.
  • Related