Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a string of hex values to a string?

Say I have a string like:

string hex = "48656c6c6f";

Where every two characters correspond to the hex representation of their ASCII, value, eg:

0x48 0x65 0x6c 0x6c 0x6f = "Hello"

So how can I get "hello" from "48656c6c6f" without having to create a lookup ASCII table? atoi() obviously won't work here.

like image 960
NullUserException Avatar asked Sep 24 '10 20:09

NullUserException


People also ask

How do you convert hex to string in Python?

To convert Python String to hex, use the inbuilt hex() method. The hex() is a built-in method that converts the integer to a corresponding hexadecimal string. For example, use the int(x, base) function with 16 to convert a string to an integer.

How do I encode a hex string?

Hex encoding is performed by converting the 8 bit data to 2 hex characters. The hex characters are then stored as the two byte string representation of the characters. Often, some kind of separator is used to make the encoded data easier for human reading.

How can I convert a hex string to an integer value?

To convert a hexadecimal string to a numberUse the ToInt32(String, Int32) method to convert the number expressed in base-16 to an integer. The first argument of the ToInt32(String, Int32) method is the string to convert. The second argument describes what base the number is expressed in; hexadecimal is base 16.


2 Answers

Hex digits are very easy to convert to binary:

// C++98 guarantees that '0', '1', ... '9' are consecutive.
// It only guarantees that 'a' ... 'f' and 'A' ... 'F' are
// in increasing order, but the only two alternative encodings
// of the basic source character set that are still used by
// anyone today (ASCII and EBCDIC) make them consecutive.
unsigned char hexval(unsigned char c)
{
    if ('0' <= c && c <= '9')
        return c - '0';
    else if ('a' <= c && c <= 'f')
        return c - 'a' + 10;
    else if ('A' <= c && c <= 'F')
        return c - 'A' + 10;
    else abort();
}

So to do the whole string looks something like this:

void hex2ascii(const string& in, string& out)
{
    out.clear();
    out.reserve(in.length() / 2);
    for (string::const_iterator p = in.begin(); p != in.end(); p++)
    {
       unsigned char c = hexval(*p);
       p++;
       if (p == in.end()) break; // incomplete last digit - should report error
       c = (c << 4) + hexval(*p); // + takes precedence over <<
       out.push_back(c);
    }
}

You might reasonably ask why one would do it this way when there's strtol, and using it is significantly less code (as in James Curran's answer). Well, that approach is a full decimal order of magnitude slower, because it copies each two-byte chunk (possibly allocating heap memory to do so) and then invokes a general text-to-number conversion routine that cannot be written as efficiently as the specialized code above. Christian's approach (using istringstream) is five times slower than that. Here's a benchmark plot - you can tell the difference even with a tiny block of data to decode, and it becomes blatant as the differences get larger. (Note that both axes are on a log scale.)

Benchmark comparison plot

Is this premature optimization? Hell no. This is the kind of operation that gets shoved in a library routine, forgotten about, and then called thousands of times a second. It needs to scream. I worked on a project a few years back that made very heavy use of SHA1 checksums internally -- we got 10-20% speedups on common operations by storing them as raw bytes instead of hex, converting only when we had to show them to the user -- and that was with conversion functions that had already been tuned to death. One might honestly prefer brevity to performance here, depending on what the larger task is, but if so, why on earth are you coding in C++?

Also, from a pedagogical perspective, I think it's useful to show hand-coded examples for this kind of problem; it reveals more about what the computer has to do.

like image 191
zwol Avatar answered Oct 22 '22 01:10

zwol


int len = hex.length();
std::string newString;
for(int i=0; i< len; i+=2)
{
    std::string byte = hex.substr(i,2);
    char chr = (char) (int)strtol(byte.c_str(), null, 16);
    newString.push_back(chr);
}
like image 22
James Curran Avatar answered Oct 21 '22 23:10

James Curran