Convert hexadecimal to decimal

In the code below, the int_of_hex function converts a hexadecimal to a decimal. Is there a built-in function that does the same thing ?
I am aware of the 0x syntax, but the naive let int_to_hex hex=0xhex;; is of course incorrect in OCaml).
Perhaps the Printf module can help here.

 exception Hexchar_exn of char;;

 let int_of_hexchar c=
    try List.assoc c
    [
      ('0', 0); ('1', 1); ('2', 2); ('3', 3); ('4', 4); ('5', 5); 
      ('6', 6); ('7', 7); ('8', 8); ('9', 9);
      ('A', 10); ('B', 11); ('C', 12); ('D', 13); ('E', 14); ('F', 15)
    ]  
    with _->raise(Hexchar_exn(c));;

 let int_of_hex s=
   let n=String.length(s) 
   and accu=ref(0) in
   for i=1 to n do accu:=int_of_hexchar(String.get s (i-1))+16*(!accu) done;
   (!accu);;

You can print an int in hexadecimal notation using the Printf module

 # Printf.printf "0x%x" 12345;;
 0x3039- : unit = ()

Also, the int_of_string function recognizes hexadecimal notation:

# int_of_string "0x3039";;
- : int = 12345

If your input string is missing the hexadecimal prefix, you can always do : int_of_string ("0x" ^ hexadecimal_string)

3 Likes

Thank you! The fact that int_of_string recognizes hexadecimal notation is very pleasant.

1 Like

Except for int_of_string which needs the 0x prefix I don’t think there such a thing in the stdlib.

Depending on what you do allocating a new string on each parse may be a bit too slow. Also in your code I would avoid using an assoc list for that.

Here would be my take on the function (man ascii may help to understand the magic constants of digit_value):

let int_of_hex s =
  let digit_value c =
    let c = Char.code c in
    if c <= 0x2F then raise_notrace Exit else
    if c <= 0x39 then c - 48 else
    if c <= 0x40 then raise_notrace Exit else
    if c <= 0x46 then c - 55 else
    if c <= 0x60 then raise_notrace Exit else
    if c <= 0x66 then c - 87 else
    raise_notrace Exit
  in
  match s with
  | "" -> None
  | s ->
      let max = String.length s - 1 in
      let rec loop i acc = match i > max with
      | true -> acc
      | false -> loop (i + 1) (acc * 16 + digit_value s.[i])
      in
      try Some (loop 0 0) with Exit -> None
3 Likes

You can also do this with Scanf:

let int_of_hex s =
  try
    Scan.sscanf s "%x%!" (fun x -> x)
  with Scanf.Scan_failure ->
    raise (* Something *)
3 Likes