Thread overview
read Hexadecimal value from string
Jul 17, 2007
Gilles G.
Jul 17, 2007
Regan Heath
Jul 17, 2007
David L. Davis
Jul 17, 2007
Frank Benoit
Jul 17, 2007
David L. Davis
Jul 17, 2007
BCS
Jul 17, 2007
Frits van Bommel
Jul 17, 2007
BCS
Jul 18, 2007
Christopher Wright
Jul 18, 2007
BCS
July 17, 2007
Hello,
I try to read hexadecimal values from a file.
I tryed to use toInt, for example:
auto i = toInt("C");
but this doesn't work.
What is the method to read hexadecimal value?

Thanks.
July 17, 2007
Gilles G. wrote:
> Hello,
> I try to read hexadecimal values from a file.
> I tryed to use toInt, for example:
> auto i = toInt("C");
> but this doesn't work.
> What is the method to read hexadecimal value?
> 
> Thanks.

Oddly, std.conv doesn't have a routine for it, as far as I am aware. Here's how I would do it.

/* http://www.opensource.org/licenses/cpl1.0.php */

import std.string, std.stdio;
import std.c.stdlib;

long hexToLong(string s)
{
	long v = strtoul(toStringz(s), null, 16);
	if (getErrno() == ERANGE) throw new Exception("Out of range");
	return v;
}

void main()
{
	writefln("%d",hexToLong("0xC"));
}
July 17, 2007
Gilles G. Wrote:

> Hello,
> I try to read hexadecimal values from a file.
> I tryed to use toInt, for example:
> auto i = toInt("C");
> but this doesn't work.
> What is the method to read hexadecimal value?
> 
> Thanks.

Hi Gilles,

    You're welcome to used some D code I wrote that's Public Domain listed below:

/+
 ' Module  : hexconv.d
 ' Author  : David L. 'SpottedTiger' Davis
 ' Tested  : dmd v2.002 (WinXP OS/ Intel CPU)
 ' Licence : Public Domain / Contributed to Digital Mars
 ' =====================================================
  ' To complie for a unittest:
 ' dmd hexconv.d -debug=hexconv -unittest
 '
 ' To compile a D program that uses hexconv.d:
 ' dmd MySource.d hexconv.d

 +/
module hexconv;

debug( hexconv ) private import std.stdio;

// Function : xtoul() - Hex string to an unsigned decimal whole number
// Author   : David 'SpottedTiger' L. Davis
// Created  : 03.May.05
// CPU      : Intel x86 (Numercials stored as "Low byte to High byte")
// Last Test: dmd v2.002
// ----------------------------------------
// Converts a Hex string from 0x0 to 0xFFFFFFFFFFFFFF
// into a ulong value 0 to 18,446,744,073,709,551,615
// also it handles the lowercase 'a' thru 'f'.
ulong xtoul(string sx)
{
    ulong  ul = 0L;
    int    j = 7;
    char   c, c1, c2;
    char[] st  = cast(char[])sx;
    int    len = st.length;

    const char[] zeros = "0000000000000000"c;
    union u { ulong ul; char[8] c; }

    u U;

    if (len == 0 || len > 16)
        throw new Exception( "xtoul() the string parameter is either an empty string,"c ~
                             " or its length is greater than 16 characters."c );

    // isHex()
    for (int i = 0; i < st.length; i++)
    {
        //c = ( sx[i] > 'F' ? sx[i] - 32 : sx[i] );
        c = st[i];

        if ((c >= '0' && c <= '9') ||
            (c >= 'A' && c <= 'F') ||
            (c >= 'a' && c <= 'f'))
           continue;
        else
          throw new Exception("xtoul() invalid hex character used."c);
    }

    if (len < 16)
        st = zeros[0..16 - len] ~ st;

    j = 7;
    for (int i = 0; i < 16; i += 2)
    {
        c1 = (st[i] > 'F' ? st[i] - 32 : st[i]);
        c2 = (st[i + 1] > 'F' ? st[i + 1] - 32 : st[i + 1]);
        c1 = cast(int)(c1 > 52 ? c1 - 55 : c1 - 48) << 4;
        U.c[j--] = c1 + cast(int)(c2 > 52 ? c2 - 55 : c2 - 48);
    }

    return U.ul;
}

unittest
{
    debug( hexconv ) writefln( "hexconv.xtoul( string ).unittest"c );
    ulong ul;

    ul = xtoul("0"c);
    assert( ul == 0x0 );
    ul = xtoul("FF"c);
    assert( ul == 0xFF );
    ul = xtoul("eea"c);
    assert( ul == 0xEEA );
    ul = xtoul("AB"c);
    assert( ul == 0xAB );
    ul = xtoul("ABCD"c);
    assert( ul == 0xABCD );
    ul = xtoul("A12CD00"c);
    assert( ul == 0xA12CD00 );
    ul = xtoul("FFFFFFFFFFFFFFFF"c);
    assert( ul == 0xFFFFFFFFFFFFFFFF );
}

// Function : ultox() - Decimal unsigned whole number to Hex string
// Author   : David 'SpottedTiger' L. Davis
// Created  : 04.May.05
// CPU      : Intel x86 (Numercials stored as "Low byte to High byte")
// Last Test: dmd v2.002
// -----------------------------------------
// Accepts any positive number from 0 to 18,446,744,073,709,551,615
// and the returns an even number of hex strings up to 16 characters
// (from 0x0 to 0xFFFFFFFFFFFFFF).
string ultox(in ulong ul)
{
    char[16] sx;
    char     c1, c2;
    union    u { ulong ul; char[8] c; }
    int      i = 0, j = 0, k = 0;
    bit      z = true;
    u U;

    U.ul = ul;

    for (i = 7; i >= 0; i--)
    {
        c1 = U.c[i] >> 4;
        c1 = cast(char)(c1 > 9 ? c1 + 55 : c1 + 48);
        c2 = U.c[i] & 0x0F;
        c2 = cast(char)(c2 > 9 ? c2 + 55 : c2 + 48);

        if (z && c1 == '0' && c2 == '0')
            continue;

        z = false;
        sx[j++] = c1;
        sx[j++] = c2;
    }

    if (j > 0)
        //Copying a fixed array into a dynamic array, must COW.
        return sx[0..j].dup;
    else
        return "00"c;
}

unittest
{
    debug( hexconv ) writefln( "hexconv.ultox( in ulong ).unittest"c );
    string sx;

    sx = ultox(0); //0x0
    assert( sx == "00"c );

    sx = ultox(255); //0xFF
    assert( sx == "FF"c );
    sx = ultox(171); //0xAB
    assert( sx == "AB"c );
    sx = ultox(43981); //0xABCD
    assert( sx == "ABCD"c );
    sx = ultox(169004288); //0xA12CD00
    assert( sx == "0A12CD00"c );
    sx = ultox(0xA12CD00); //169004288
    assert( sx == "0A12CD00"c );

    sx = ultox(ulong.max); //0xFFFFFFFFFFFFFFFF
    assert( sx == "FFFFFFFFFFFFFFFF"c );
}

bool isHex(string sx)
{
    char c;

    for (int i = 0; i < sx.length; i++)
    {
        c = sx[i];

        if ((c >= '0' && c <= '9') ||
            (c >= 'A' && c <= 'F') ||
            (c >= 'a' && c <= 'f'))
            continue;
        else
            return false;
    }

    return true;
}

unittest
{
    debug( hexconv ) writefln( "hexconv.isHex( string ).unittest"c );

    assert( isHex("00"c) );
    assert( isHex("FF"c) );
    assert( isHex("Ffae0"c) );
    assert( isHex("AB"c) );
    assert( isHex("abdef"c) );
    assert( isHex("ABCD"c) );
    assert( isHex("0A12CD00"c) );
    assert( isHex("FFFFFFFFFFFFFFFF"c) );

    assert( isHex("00ER"c) == false );
    assert( !isHex("0xW"c) );
}

debug( hexconv )
{
int main()
{
    auto i = xtoul("C");

    writefln("i=%d, xtoul(\"C\")=%d, ultox(i)=\"%s\"", i, xtoul("C"), ultox(i));
    writefln( "unittest done"c );
    return 0;
}
}

Best Regards,

David L. Davis
July 17, 2007
When using Tango, this can be done like this:

import tango.text.convert.Integer;
int  i = toInt( "12AB", 16 );
long l = toLong( "ffffFFFFAAAA", 16 );

see also:
http://www.dsource.org/projects/tango/wiki/ChapterConversions
and the source at
http://www.dsource.org/projects/tango/browser/trunk/tango/text/convert/Integer.d

Frank
July 17, 2007
Frank Benoit Wrote:

> When using Tango, this can be done like this:
> 
> import tango.text.convert.Integer;
> int  i = toInt( "12AB", 16 );
> long l = toLong( "ffffFFFFAAAA", 16 );
> 
> see also:
> http://www.dsource.org/projects/tango/wiki/ChapterConversions
> and the source at
> http://www.dsource.org/projects/tango/browser/trunk/tango/text/convert/Integer.d
> 
> Frank

Yep, Tango has some very kool functions. But I do want to point out that Phobos does have a radix parameter in the toString functions for converting a number to a string...sadly not the other way around.

Here's an example:
// Using Phobos you can convert a long or a ulong value,
// using any base from 2 to 36 into a string
private import ss = std.string;
private import io = std.stdio;

void main()
{
    auto s = ss.toString(12uL, 16u);
    io.writefln("ss.toString(12uL, 16u)=\"%s\"", s);
}

/+ Output:
C:\dmd>dmd strex1.d
C:\dmd\bin\..\..\dm\bin\link.exe strex1,,,user32+kernel32/noi;

C:\dmd>strex1
ss.toString(12uL, 16u)="C"

C:\dmd>
+/

David L. Davis
July 17, 2007
Reply to David,

> Yep, Tango has some very kool functions. But I do want to point out
> that Phobos does have a radix parameter in the toString functions for
> converting a number to a string...sadly not the other way around.
> 

OK, brute force it is ;-b 

|T fromString(T)(char[] str, uint r)
|{
|  T v = T.min;
|  goto start;
|  do
|  {
|    v++;
|  start:
|    if(toString(v,r) == str) return v;
|  }while(v != T.max);
|}

(bonus points if you can find more than three things to object to.)


July 17, 2007
BCS wrote:
> Reply to David,
> 
>> Yep, Tango has some very kool functions. But I do want to point out
>> that Phobos does have a radix parameter in the toString functions for
>> converting a number to a string...sadly not the other way around.
>>
> 
> OK, brute force it is ;-b
> |T fromString(T)(char[] str, uint r)
> |{
> |  T v = T.min;
> |  goto start;
> |  do
> |  {
> |    v++;
> |  start:
> |    if(toString(v,r) == str) return v;
> |  }while(v != T.max);
> |}

:P

> (bonus points if you can find more than three things to object to.)

Without actually compiling that, I'll list some objections:
1) Let's get this one out of the way first: it's brute force. I mean, come on!
2) Since toString outputs uppercase characters (for digits > 9), this doesn't work for strings containing lowercase characters as digits.
3) It generates a lot of heap activity for anything that doesn't happen to be close to T.min (one string per iteration). Probably especially problematic for applications with small signed numbers or big numbers. This will probably mean lots of GC cycles. Arguably a symptom of (1).
4) It doesn't allow a redundant '+' at the start :P.
5) It appears from the Phobos source that toString(long value, uint radix) doesn't properly handle negative numbers when radix != 10. Though I guess that's a Phobos issue, not an issue in your code this cause the return value (if any[1]) answer given to be negative for T == long.

After compiling (and verifying all above issues):
6) Doesn't compile for T other than long or ulong due to overload resolution issues (those are the only two types toString(T, uint radix) is defined for).
7) Very bad error checking. Out-of-range or plain invalid input (and input triggering (2), (4) and/or (5)) results in a failed assertion at the end of the function due to no return statement being executed. And if compiled in release mode it segfaults (executing a 'hlt' instruction put there by the implicit assert(0) at the end of the function).

Did I miss anything?

[1]: Due to some of the other issues, control may reach the end of the function without returning anything.
July 17, 2007
Reply to Frits,

> BCS wrote:
> 
>> Reply to David,
>> 
>>> Yep, Tango has some very kool functions. But I do want to point out
>>> that Phobos does have a radix parameter in the toString functions
>>> for converting a number to a string...sadly not the other way
>>> around.
>>> 
>> OK, brute force it is ;-b
>> |T fromString(T)(char[] str, uint r)
>> |{
>> |  T v = T.min;
>> |  goto start;
>> |  do
>> |  {
>> |    v++;
>> |  start:
>> |    if(toString(v,r) == str) return v;
>> |  }while(v != T.max);
>> |}
> :P
> 
>> (bonus points if you can find more than three things to object to.)
>> 
> Without actually compiling that, I'll list some objections:
> 1) Let's get this one out of the way first: it's brute force. I mean,
> come on!

i++

> 2) Since toString outputs uppercase characters (for digits > 9), this
> doesn't work for strings containing lowercase characters as digits.

i++

> 3) It generates a lot of heap activity for anything that doesn't
> happen
> to be close to T.min (one string per iteration). Probably especially
> problematic for applications with small signed numbers or big numbers.
> This will probably mean lots of GC cycles. 

> Arguably a symptom of (1).

i += 0

> 4) It doesn't allow a redundant '+' at the start :P.

i++

> 5) It appears from the Phobos source that toString(long value, uint
> radix) doesn't properly handle negative numbers when radix != 10.
> Though

> I guess that's a Phobos issue, not an issue in your code this cause
> the return value (if any[1]) answer given to be negative for T == long.
> After compiling (and verifying all above issues):

i+=0

> 6) Doesn't compile for T other than long or ulong due to overload
> resolution issues (those are the only two types toString(T, uint
> radix)
> is defined for).


> 7) Very bad error checking. Out-of-range or plain invalid input (and
> input triggering (2), (4) and/or (5)) results in a failed assertion at
> the end of the function due to no return statement being executed. And
> if compiled in release mode it segfaults (executing a 'hlt'
> instruction
> put there by the implicit assert(0) at the end of the function).

i += ulong.max

i>3 => bonus points <g>

> Did I miss anything?
> 

goto!!!


> [1]: Due to some of the other issues, control may reach the end of the
> function without returning anything.
> 


July 18, 2007
BCS wrote:
> Reply to David,
> 
>> Yep, Tango has some very kool functions. But I do want to point out
>> that Phobos does have a radix parameter in the toString functions for
>> converting a number to a string...sadly not the other way around.
>>
> 
> OK, brute force it is ;-b
> |T fromString(T)(char[] str, uint r)
> |{
> |  T v = T.min;
> |  goto start;
> |  do
> |  {
> |    v++;
> |  start:
> |    if(toString(v,r) == str) return v;
> |  }while(v != T.max);
> |}
> 
> (bonus points if you can find more than three things to object to.)
> 
> 

1. Using a for loop would be much clearer.
2. Using a goto is generally frowned upon; local gotos, though, especially in such simple cases, are usually readable. However, most programmers react viscerally to gotos. It is recommended that you avoid them unless you want your viscera removed.
3. In general, you shouldn't use != for loop boundaries unless *all* possible values other than that single value is still valid for the guts of the loop. If you were to refactor and make v into a real for all cases, for instance, you'd do a lot more work than necessary.
4. There is not guaranteed to be a toString(T, uint) method. T is not guaranteed to have increment and decrement overloads.

On the plus side, this executes in constant time and is a good example of code reuse.

For this, though, I think I'd use annealing. It's probably a bit faster, especially if I had several annealings executing in parallel.
July 18, 2007
Christopher Wright wrote:
> BCS wrote:
> 
>> Reply to David,
>>
>>> Yep, Tango has some very kool functions. But I do want to point out
>>> that Phobos does have a radix parameter in the toString functions for
>>> converting a number to a string...sadly not the other way around.
>>>
>>
>> OK, brute force it is ;-b
>> |T fromString(T)(char[] str, uint r)
>> |{
>> |  T v = T.min;
>> |  goto start;
>> |  do
>> |  {
>> |    v++;
>> |  start:
>> |    if(toString(v,r) == str) return v;
>> |  }while(v != T.max);
>> |}
>>
>> (bonus points if you can find more than three things to object to.)
>>
>>
> 
> 1. Using a for loop would be much clearer.

i++
> 2. Using a goto is generally frowned upon; local gotos, though, especially in such simple cases, are usually readable. However, most programmers react viscerally to gotos. It is recommended that you avoid them unless you want your viscera removed.

i++
//AAAaahh!!! ;)

> 3. In general, you shouldn't use != for loop boundaries unless *all* possible values other than that single value is still valid for the guts of the loop. If you were to refactor and make v into a real for all cases, for instance, you'd do a lot more work than necessary.
i++

> 4. There is not guaranteed to be a toString(T, uint) method. T is not guaranteed to have increment and decrement overloads.
> 
i+=2

> On the plus side, this executes in constant time and is a good example of code reuse.
> 
> For this, though, I think I'd use annealing. It's probably a bit faster, especially if I had several annealings executing in parallel.

i-= large_number
// that's even worse then mine!!

//nice breakdown (bonus points to you)