Довольно напечатать ByteString в шестнадцатеричном формате

Каков идиоматический способ обработки байтовой строки по кусочкам и красивой печати ее шестнадцатеричного (0-F) представления?

putStrLn . show . B.unpack
-- [1,126]

Который при дальнейшей работе

putStrLn . show . map (\x -> N.showIntAtBase 16 (DC.intToDigit) x "") . B.unpack
["1","7e"]

Но чего я действительно хочу, так это

["1","7","e"]

Или еще лучше

['1','7','e']

Я мог бы испортить ["1","7e"] но эту манипуляцию со строками, тогда как я бы предпочел манипуляции с числами. Нужно ли мне переходить к смещению и маскированию числовых значений?


person xrl    schedule 07.12.2011    source источник


Ответы (4)


Я хотел бы уточнить ответ Макса Талдыкина (за который я проголосовал), который я считаю слишком сложным. Нет необходимости в NoMonomorphismRestriction, printf или Data.List.

Вот моя версия:

import qualified Data.ByteString as B
import Numeric (showHex)

prettyPrint :: B.ByteString -> String
prettyPrint = concat . map (flip showHex "") . B.unpack

main :: IO ()
main = putStrLn . prettyPrint . B.pack $ [102, 117, 110]
person lbolla    schedule 07.12.2011
comment
Здесь вы испортите результат, так как showHex не будет дополнено 2. - person Peaker; 12.06.2012
comment
@Peaker прав, это решение неверно. Он отсекает все начальные нули. ответ crokea внизу правильный. - person Xander Dunn; 15.03.2017

Теперь вы можете использовать Data.ByteString.Builder. Чтобы напечатать ByteString в его шестнадцатеричном эквиваленте (с двумя шестнадцатеричными цифрами на байт, в правильном порядке и эффективно), просто используйте:

toLazyByteString . byteStringHex

or

toLazyByteString . lazyByteStringHex

в зависимости от того, какой вкус ByteString у вас есть на входе.

person crockeea    schedule 24.02.2016

Что-то вроде этого:

{-# LANGUAGE NoMonomorphismRestriction #-}

import qualified Data.ByteString as B
import Text.Printf
import Data.List
import Numeric

hex = foldr showHex "" . B.unpack
list = printf "[%s]" . concat . intersperse "," . map show

Контрольная работа:

> let x = B.pack [102,117,110]
> list . hex $ x
"['6','6','7','5','6','e']"

Upd Ой, тут дурацкая утечка памяти: конечно надо заменить foldr на foldl' (ибо лень тут не требуется):

hex = foldl' (flip showHex) "" . B.unpack
person max taldykin    schedule 07.12.2011
comment
Конечно, версия foldl' печатает байты в обратном порядке, с прямым порядком байтов. - person crockeea; 24.02.2016

У вас есть ["1","7e"] :: [String] concat ["1", "7e"] равно "17e" :: String, что равно [Char] и равно ['1','7','e'] :: [Char].

Затем вы можете разделить эту строку на части:

> Data.List.Split.splitEvery 1 . concat $ ["1", "7e"]
["1","7","e"]
it :: [[Char]]
person ДМИТРИЙ МАЛИКОВ    schedule 07.12.2011