我有字节数组作为输入。我想将该数组转换为包含数组值的十六进制表示的字符串。这是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,我尝试了列表,但我能得到的最好的是数组或字符串列表。
问题:
示例输入:[| 0x24uy; 0xA1uy; 0x00uy; 0x1Cuy |]应该产生字符串“24A1001C”
答案 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#,我可能会使用类似的地方(其中raw
是byte[]
参数):
StringBuilder sb = new StringBuilder();
foreach (byte b in raw) {
sb.Append(b.ToString("x2"));
}
return sb.ToString()
我想知道这是如何转化为F#...