f # byte [] -> hex -> преобразование строк - PullRequest
6 голосов
/ 21 декабря 2008

У меня есть байтовый массив в качестве входных данных. Я хотел бы преобразовать этот массив в строку, которая содержит шестнадцатеричное представление значений массива. Это код 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 из сборки System?

Пример ввода: [| 0x24uy; 0xA1uy; 0x00uy; 0x1Cuy |] должен выдать строку "24A1001C"

Ответы [ 6 ]

9 голосов
/ 21 декабря 2008

В вашем примере нет ничего неправильного. Если вы хотите свести его к одному выражению, используйте метод 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.

5 голосов
/ 29 марта 2016

Если вы хотите преобразовать и накопить за один шаг, 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"
3 голосов
/ 25 мая 2012

Вот еще один ответ:

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.

2 голосов
/ 01 июня 2018

Вот еще один. Я изучаю F #, поэтому не стесняйтесь поправлять меня с помощью более идиоматических способов сделать это:

let bytesToHexString (bytes : byte[]) : string =
    bytes
    |> Seq.map (fun c -> c.ToString("X2"))
    |> Seq.reduce (+)
1 голос
/ 22 декабря 2008

выглядит хорошо для меня. Просто чтобы указать на другую, на мой взгляд, очень полезную функцию в модуле Printf, взгляните на ksprintf. Он передает результат отформатированной строки в функцию по вашему выбору (в данном случае, в функцию тождества).

val ksprintf : (string -> 'd) -> StringFormat<'a,'d> -> 'a  
    sprintf, but call the given 'final' function to generate the result.
0 голосов
/ 21 декабря 2008

Если честно, это не выглядит ужасно (хотя у меня также есть очень небольшой опыт F #). Предлагает ли F # простой способ итерации (foreach)? Если бы это был C #, я мог бы использовать что-то вроде (где raw является аргументом byte[]):

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

Интересно, как это переводится на F # ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...