views:

361

answers:

6

I am writing a string parser and the thought occurred to me that there might be some really interesting ways to convert an ASCII hexadecimal character [0-9A-Fa-f] to it's numeric value.

What are the quickest, shortest, most elegant or most obscure ways to convert [0-9A-Fa-f] to it's value between 0 and 15?

Assume, if you like, that the character is a valid hex character.

I have no chance so I'll have a go at the most boring.

( c <= '9' ) ? ( c - '0' ) : ( (c | '\x60') - 'a' + 10 )
A: 

In C you can so something like:

if(isdigit(c)) 
  num = c -'0';
else if(c>='a' && c<='f')
  num = 10 + c - 'a';
else if(c>='A' && c<='F')
  num = 10 + c - 'A';
codaddict
A: 

In JavaScript:

num = parseInt(hex, 16);
scunliffe
A: 

One simple way is to look for it in a string:

int n = "0123456789ABCDEF".IndexOf(Char.ToUpper(c));

Another way is to convert it as a digit, and then check if it's a character:

int n = Char.ToUpper(c) - '0';
if (n > 9) n -= 7;
Guffa
A: 

Here's the boring C version (and my C is very rusty, so it's probably wrong as well).

char parseIntChar(const char p) {
  char c[2];
  c[0]=p;
  c[1]=0;
  return strtol(c,0,16);
}
Joachim Sauer
+2  A: 

(c&15)+(c>>6)*9

In response to "How does it work", it throws away enough bits so that the numbers map to [0:9] and the letters map to [1:6], then adds 9 for the letters. The c>>6 is a surrogate for if (c >= 64) ....

Marcelo Cantos
Nice. I have one question: how does it work?
philcolbourn
David V.
+1 , its nice. doesn't work with lowercase letters though, but it can be modified to.
David V.
@David V: I think it does work for upper and lower case. I tested it, and it does work.
philcolbourn
With no comparisons or jumps, this is probably the quickest and smallest. 14 bytes with gcc -O3.
philcolbourn
gcc multiplies by `9` by `(c>>6<<3)+(c>>6)` or `c/64*8 + c/64`
philcolbourn
I stand corrected, lowercase chars are 0110xxxx which still gives 1 when shifted right 6 times. I wrote too fast.
David V.
Very nice! It does indeed work for both upper and lower case - tested in C.
Evgeny
A: 
private byte[] HexStringToBytes( string hexString )
{
    byte[] bytes = ASCIIEncoding.ASCII.GetBytes(hexString);
    byte[] ret = new byte[bytes.Length / 2];
    for (int i = 0; i < bytes.Length; i += 2)
    {
       byte hi = (byte)(((bytes[i] & 0x40) == 0) ? bytes[i] & 0x0F : bytes[i] & 0x0F + 9);
       byte lo = (byte)(((bytes[i+1] & 0x40) == 0) ? bytes[i+1] & 0x0F : bytes[i+1] & 0x0F + 9);
       ret[i / 2] = (byte)((hi << 4) | lo);
    }
    return ret;
}
Meat Popsicle