Erlang io:formatting a binary to hex

2019-02-03 03:54发布

Can I format an Erlang binary so that each byte is written in hex? I.e.,

> io:format(???, [<<255, 16>>]).
<<FF, 10>>

I don't see an obvious way to do it in io:format documentation, but perhaps I am simply missing one? Converting a binary to list and formatting its elements separately is too inefficient.

标签: binary erlang
7条回答
成全新的幸福
2楼-- · 2019-02-03 04:30

Improving upon @hairyhum

This takes care of zero paddings << <<Y>> ||<<X:4>> <= Id, Y <- integer_to_list(X,16)>>

reverse transformation <<<<Z>> || <<X:8,Y:8>> <= Id,Z <- [binary_to_integer(<<X,Y>>,16)]>>, %%hex to binary

查看更多
小情绪 Triste *
3楼-- · 2019-02-03 04:31

Here is another short and fast version which I use:

hexlify(Bin) when is_binary(Bin) ->
    << <<(hex(H)),(hex(L))>> || <<H:4,L:4>> <= Bin >>.

hex(C) when C < 10 -> $0 + C;
hex(C) -> $a + C - 10.
查看更多
Emotional °昔
4楼-- · 2019-02-03 04:37

if you prefer to make a binary string instead of erlang default list strings, you may use binary comprehension syntax, like what I did on my sha1 generating code:

1> << << if N >= 10 -> N -10 + $a;
1>          true    -> N     + $0 end >>
1>    || <<N:4>> <= crypto:hash(sha, "hello world") >>.
<<"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed">>

same as in python binascii.b2a_hex:

>>> binascii.b2a_hex(sha.new('hello world').digest())
'2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'
查看更多
可以哭但决不认输i
5楼-- · 2019-02-03 04:43
bin_to_hex_list(Bin) when is_binary(Bin) ->
  lists:flatten([integer_to_list(X,16) || <<X>> <= Bin]).
查看更多
男人必须洒脱
6楼-- · 2019-02-03 04:50

You could do: [ hd(erlang:integer_to_list(Nibble, 16)) || << Nibble:4 >> <= Binary ].

Which would return you a list(string) containing the hex digits of the binary. While I doubt the efficiency of this operation is going to have any effect on the runtime of your system, you could also have this bin_to_hex function return an iolist which is simpler to construct and will be flattened when output anyway. The following function returns an iolist with the formatting example you gave:

bin_to_hex(Bin) when is_binary(Bin) ->
    JoinableLength = byte_size(Bin) - 1,
    << Bytes:JoinableLength/binary, LastNibble1:4, LastNibble2:4 >> = Bin,
    [ "<< ",
      [ [ erlang:integer_to_list(Nibble1, 16), erlang:integer_to_list(Nibble2, 16), ", " ]
        || << Nibble1:4, Nibble2:4 >> <= Bytes ],
      erlang:integer_to_list(LastNibble1, 16),
      erlang:integer_to_list(LastNibble2, 16),
      " >>" ].

It's a bit ugly, but runs through the binary once and doesn't traverse the output list (otherwise I'd have used string:join to get the interspersed ", " sequences). If this function is not the inner loop of some process (I have a hard time believing this function will be your bottleneck), then you should probably go with some trivially less efficient, but far more obvious code like:

bin_to_hex(Bin) when is_binary(Bin) ->
    "<< " ++ string:join([byte_to_hex(B) || << B >> <= Bin ],", ") ++ " >>".

byte_to_hex(<< N1:4, N2:4 >>) ->
    [erlang:integer_to_list(N1, 16), erlang:integer_to_list(N2, 16)].
查看更多
The star\"
7楼-- · 2019-02-03 04:53

This hasn’t seen any action for a while, but all of the prior solutions seem overly convoluted. Here’s what, for me, seems much simpler:

[begin if N < 10 -> 48 + N; true -> 87 + N end end || <<N:4>> <= Bin]

If you prefer it expanded a bit:

[begin
    if
        N < 10 ->
            48 + N; % 48 = $0
        true ->
            87 + N  % 87 = ($a - 10)
    end
end || <<N:4>> <= Bin]
查看更多
登录 后发表回答