f#byte [] - > hex - >字符串转换

时间:2008-12-21 13:07:13

标签: f#

我有字节数组作为输入。我想将该数组转换为包含数组值的十六进制表示的字符串。这是F#代码:

let ByteToHex bytes = 
    bytes 
    |> Array.map (fun (x : byte) -> String.Format("{0:X2}", x))

let ConcatArray stringArray = String.Join(null, (ByteToHex  stringArray))

这会产生我需要的结果,但我想让它更紧凑,以便我只有一个功能。 我找不到能在最后连接每个字节的字符串表示的函数 ByteToHex。
我尝试了Array.concat,concat_map,我尝试了列表,但我能得到的最好的是数组或字符串列表。

问题:

  1. 这样做最简单,最优雅的方式是什么?
  2. F#中是否有字符串格式化构造,以便我可以从系统程序集中替换String.Format?
  3. 示例输入:[| 0x24uy; 0xA1uy; 0x00uy; 0x1Cuy |]应该产生字符串“24A1001C”

6 个答案:

答案 0 :(得分:9)

你的例子没有任何内在错误。如果您想将其归结为单个表达式,请使用String.contcat方法。

let ByteToHex bytes = 
    bytes 
    |> Array.map (fun (x : byte) -> System.String.Format("{0:X2}", x))
    |> String.concat System.String.Empty

在引擎盖下,String.concat将只调用String.Join。您的代码可能必须稍作修改,因为根据您的示例导入系统。这可能会在F#String和System.String之间产生名称解析冲突。

答案 1 :(得分:5)

如果您想一步变换和积累,fold就是您的答案。 sprintf是F#字符串格式函数。

let ByteToHex (bytes:byte[]) =
    bytes |> Array.fold (fun state x-> state + sprintf "%02X" x) ""

这也可以使用StringBuilder

完成
open System.Text

let ByteToHex (bytes:byte[]) =
        (StringBuilder(), bytes)
        ||> Array.fold (fun state -> sprintf "%02X" >> state.Append)  
        |> string

产生

[|0x24uy; 0xA1uy; 0x00uy; 0x1Cuy|] |> ByteToHex;;
val it : string = "24A1001C"

答案 2 :(得分:3)

这是另一个答案:

let hashFormat (h : byte[]) =
  let sb = StringBuilder(h.Length * 2)
  let rec hashFormat' = function
    | _ as currIndex when currIndex = h.Length -> sb.ToString()
    | _ as currIndex ->
      sb.AppendFormat("{0:X2}", h.[currIndex]) |> ignore
      hashFormat' (currIndex + 1)
  hashFormat' 0

这个的优点是它是尾递归的,它预先在字符串构建器中分配确切的空间量,这将把字节数组转换为十六进制字符串。

对于上下文,我在这个模块中有它:

module EncodingUtils

open System
open System.Text
open System.Security.Cryptography
open Newtonsoft.Json

let private hmacmd5 = new HMACMD5()
let private encoding = System.Text.Encoding.UTF8
let private enc (str : string) = encoding.GetBytes str
let private json o = JsonConvert.SerializeObject o
let md5 a = a |> (json >> enc >> hmacmd5.ComputeHash >> hashFormat)

意思是我可以传递md5任何对象并获取它的JSON哈希值。

答案 3 :(得分:2)

这是另一个。我正在学习F#,所以我可以用更惯用的方式来纠正我:

let bytesToHexString (bytes : byte[]) : string =
    bytes
    |> Seq.map (fun c -> c.ToString("X2"))
    |> Seq.reduce (+)

答案 4 :(得分:1)

对我来说很好看。在我看来,只是指出另一个在Printf模块中非常有用的功能,看看ksprintf。它将格式化字符串的结果传递给您选择的函数(在本例中为标识函数)。

val ksprintf : (string -> 'd) -> StringFormat<'a,'d> -> 'a  
    sprintf, but call the given 'final' function to generate the result.

答案 5 :(得分:-1)

说实话,这看起来并不可怕(虽然我也有非常小F#体验)。 F#是否提供了一种简单的迭代方法(foreach)?如果这是C#,我可能会使用类似的地方(其中rawbyte[]参数):

        StringBuilder sb = new StringBuilder();
        foreach (byte b in raw) {
            sb.Append(b.ToString("x2"));
        }
        return sb.ToString()

我想知道这是如何转化为F#...