open System
open System.Globalization

let hexStringToBytes s =
Array.init (s.Length / 2) (fun i -> s.Substring(2*i, 2))
|> Array.map (fun b -> Byte.Parse(b, NumberStyles.AllHexSpecifier))

By on 7/17/2007 9:10 PM ()

Thanks.

Unfortunately, I'm getting an index out of bounds exception.

If I understand it correctly, you're basically splitting the string into two-character substrings, and parsing each one to a byte?

By on 7/18/2007 8:45 AM ()

Yes, you understood Gregs code correctly. It didn't work because of one detail - the second argument to the Substring should be length (2) instead of the index of the end location (2*i + 2). You can then use similar trick to get an array of BigNums - you first split the array of bytes into array of arrays using Array.init (where the inner array contains exactly 16 bytes) and than use Array.map to convert every 16 bytes to BigNum. I don't know if there is any function to do this last step automatically, but it is not that difficult to write (see the bytesToBigNum function):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
#light

open System
open System.Globalization
open Microsoft.FSharp.Math

let hexStringToBytes (s:string) =
  Array.init (s.Length / 2) (fun i -> s.Substring(2*i, 2))
  |> Array.map (fun b -> Byte.Parse(b, NumberStyles.AllowHexSpecifier))

let bytesToBigNum bt =
  bt |> Array.fold_left (fun st b -> st*256N + (BigNum.of_int (int b))) BigNum.zero

let bytesToBigNums (bt:byte[]) = 
  Array.init (bt.Length / 16) (fun i -> Array.sub bt (i*16) 16)
  |> Array.map bytesToBigNum
By on 7/18/2007 12:15 PM ()

I was just about to post what I'd ended up with, to verify that it was correct, but you beat me to it. I should check my notification settings :)

Anyway, thanks for the help. Once I realized that the Substring function was looking for a length, I was set :)

Is there any meaningful difference between a byte[] and a byte array? VStudio shows them as two different types in the mouseover text, and it's making me curious. I'm combining a bunch of these into a byte array to send over a socket, and I'd like to make sure that I'm not doing anything wonky in the process :)

Thanks!

By on 7/18/2007 1:25 PM ()

Hi, there was a difference between "byte[]" and "byte array" in F# for earlier versions of .NET (though I'm not sure what was the difference and why it was there). Anyway, the types are equal if you use .NET 2.0.

By on 7/18/2007 1:48 PM ()

Sorry to be asking so many questions, but does anyone have any suggestions on doing the reverse process, going from an array of bytes back to a hex string?

Thanks yet again!

By on 7/20/2007 1:10 PM ()

After some poking around, I found something that I think is working, though it seems a bit clumsy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let hexDigits =   [|
        "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7";
        "8"; "9"; "a"; "b"; "c"; "d"; "e"; "f";
    |];; 
    
let bytesToHexString (data : byte[]) =
    let mutable str = "" in
    for i = 0 to (data.Length - 1) do
        let byteVal = data.[i] in
        let first = Byte.shift_right byteVal 4 in
        let second = System.Int32.Parse(byteVal.ToString()) &&& 0xF in
        let hexChar1 = hexDigits.[ System.Int32.Parse(first.ToString()) ] in
        let hexChar2 = hexDigits.[ second ] in
        str <- str + hexChar1 + hexChar2;
    done;
    str;;
By on 7/20/2007 2:28 PM ()

We can take advatage of the .ToString("x"), which formats a byte as hex. There may even be a format string that tells it to format the byte as a two digit hex string, but I haven't found it. So, how about the following:

1
2
3
4
5
6
7
8
9
10
open System

let byteArrayToString (x : byte[]) =
    x 
    |> Array.map (fun b -> (if b < 16uy then "0" else "") + b.ToString("x"))
    |> Array.fold_left (fun acc x -> acc + x) ""
    
do printf "%s" (byteArrayToString [| 1uy; 2uy; 3uy; 4uy; 5uy; 6uy; 
                                     7uy; 8uy; 9uy; 10uy; 11uy; 12uy; 
                                     13uy; 14uy; 15uy; 16uy; |])
By on 7/20/2007 8:23 PM ()

Hi,

A few tips:

1
2
3
4
  [| 1uy; 2uy; 3uy; 4uy; 5uy; 6uy;
  7uy; 8uy; 9uy; 10uy; 11uy; 12uy;
  13uy; 14uy; 15uy; 16uy; |]

can also be written:

1
  [|1uy .. 16uy|]

and:

1
  Array.fold_left (fun acc x -> acc + x) ""

might be written:

1
  Array.fold_left (+) ""

Using list comprehension, you can also shorten it a bit. It's just a question of syntax. Robert's code becomes:

1
2
3
4
5
6
7
8
9
10
11
12
#light
open System 


let byteArrayToString (x : byte[]) =
  [|for b in x -> (if b < 16uy then "0" else "") + b.ToString("x")|]
  |> Array.fold_left (+) ""


printf "%s" (byteArrayToString [|1uy .. 16uy|])

I hope it's helpful.

--
Laurent.

By on 7/21/2007 6:39 AM ()

You can also use the "%02" printf pattern, e.g.

1
2
3
4
5
6
7
8
 

let byteArrayToString (x : byte[]) =
  String.concat "" [ for b in x -> sprintf "%02x" b ]

printf "%s" (byteArrayToString [|1uy .. 16uy|])

kind regards

don

By on 7/22/2007 4:11 PM ()

Thanks for the input, all of you.

This proves that mini-projects really ARE a good way to learn a new language :)

After this project, I have concluded that I like F#, and want to continue using it.

By on 7/23/2007 2:59 PM ()

Good to know. Thanks!

By on 7/20/2007 10:41 AM ()

Yes, that's right, but the Substring method doesn't work as I remembered it: the second argument is a length not an end index. The code should work now.

By on 7/18/2007 12:08 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper