1

I am looking for an easy and elegant way for parsing numbers (dec and hex) with stringstream (or istringstream or some other Std-C++ class).

Valid input for a decimal number of e.g. 11 should be 11 0xb bh

Normally I would use a regular expression but it is not possible here because of missing libraries and oder C++ compiler.

Thanks!

chris01
  • 10,921
  • 9
  • 54
  • 93

2 Answers2

2

It may be silly but IMHO simplest solution is std::stringstream + std::hex (and others)

unsigned int x;   
std::stringstream ss;
ss << std::hex << "0xb";
ss >> x;
stryku
  • 722
  • 5
  • 12
  • I was thinking tooo complicated. – chris01 Mar 16 '17 at 13:34
  • Doesn't work generically for the possible input defined by OP: `11 0xb bh`. It will set x to `17` for input `11`. – zett42 Mar 16 '17 at 16:44
  • @zett42 My code is just an example for hex strings. I think `11 0xb bh` were just three possible inputs in three different number systems. In link that I posted there are manipulators for these systems. And from OP's comment to this answer I conclude that it helped him - and that was the goal. – stryku Mar 17 '17 at 08:28
  • My point is, simply setting `std::hex` is not enough to parse the possible kind of inputs *automatically*, you have to know in advance the numbering system for each input which kinda defeats the purpose. Btw, `bh` is just a different notation for `0xb`, which can't be parsed using `std::hex` or any of the other linked manipulators. – zett42 Mar 17 '17 at 09:43
0

I may be missing something but I think that the default istream::operator >> is not able to detect base automatically from the input. The manipulator std::hex can only be used to force the base to 16 but it will be applied to all input without regard for prefix "0x" or suffix "h".

We can work around by overloading operator >> for a custom type and call std::stoi():

struct ParsedInt
{
    int val;
};

inline std::istream& operator>>( std::istream& strm, ParsedInt& i )
{
    std::string s; strm >> s;
    i.val = 0;

    if( ! s.empty() )
    {
        if( s.back() == 'h' )
            // explicitly use base 16 to parse hex
            i.val = static_cast<int>( std::stoul( s, nullptr, 16 ) );
        else
            // stoi() with base 0 will detect prefix "0x".
            i.val = static_cast<int>( std::stoul( s, nullptr, 0 ) );
    }

    return strm;
}

Usage example:

int main()
{
    std::stringstream ss( "11 0xb bh -11 0xffffffff fffffffeh" );

    ParsedInt i;
    while( ss >> i )
    {
        std::cout << i.val << "\n";
    }
}

Output:

11
11    
11    
-11    
-1    
-2

Live Demo.

Edit:

Original code crashed with std::out_of_range exceptions for negative hex numbers like 0xFFFFFFFF, this has been fixed by replacing std::stoi() with std::stoul() and static_casting the result to int.

zett42
  • 25,437
  • 3
  • 35
  • 72