2010-09-22 43 views
17

Tôi có thể định dạng nhị phân Erlang sao cho mỗi byte được viết bằng hex? Ví dụ:Erlang io: định dạng nhị phân thành hex

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

Tôi không thấy một cách rõ ràng để làm điều đó trong io:format tài liệu, nhưng có lẽ tôi chỉ đơn giản là thiếu một? Việc chuyển đổi nhị phân thành danh sách và định dạng các phần tử riêng rẽ của nó là không hiệu quả.

Trả lời

21

Không, đó không phải là lựa chọn các định dạng như vậy nhưng bạn có thể làm điều gì đó như:

io:format("<<~s>>~n", [[io_lib:format("~2.16.0B",[X]) || <<X:8>> <= <<255,16>> ]]). 

Có giải pháp nhanh hơn rất nhiều nếu bạn cần.

-module(bin_to_hex). 

-compile([native, {hipe, [o3]}]). 

-export([bin_to_hex/1]). 

bin_to_hex(B) when is_binary(B) -> 
    bin_to_hex(B, <<>>). 

-define(H(X), (hex(X)):16). 

bin_to_hex(<<>>, Acc) -> Acc; 
bin_to_hex(Bin, Acc) when byte_size(Bin) band 7 =:= 0 -> 
    bin_to_hex_(Bin, Acc); 
bin_to_hex(<<X:8, Rest/binary>>, Acc) -> 
    bin_to_hex(Rest, <<Acc/binary, ?H(X)>>). 

bin_to_hex_(<<>>, Acc) -> Acc; 
bin_to_hex_(<<A:8, B:8, C:8, D:8, E:8, F:8, G:8, H:8, Rest/binary>>, Acc) -> 
    bin_to_hex_(
    Rest, 
    <<Acc/binary, 
     ?H(A), ?H(B), ?H(C), ?H(D), ?H(E), ?H(F), ?H(G), ?H(H)>>). 

-compile({inline, [hex/1]}). 

hex(X) -> 
    element(
    X+1, {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 
      16#3037, 16#3038, 16#3039, 16#3041, 16#3042, 16#3043, 16#3044, 
      16#3045, 16#3046, 16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 
      16#3135, 16#3136, 16#3137, 16#3138, 16#3139, 16#3141, 16#3142, 
      16#3143, 16#3144, 16#3145, 16#3146, 16#3230, 16#3231, 16#3232, 
      16#3233, 16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 
      16#3241, 16#3242, 16#3243, 16#3244, 16#3245, 16#3246, 16#3330, 
      16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 
      16#3338, 16#3339, 16#3341, 16#3342, 16#3343, 16#3344, 16#3345, 
      16#3346, 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 
      16#3436, 16#3437, 16#3438, 16#3439, 16#3441, 16#3442, 16#3443, 
      16#3444, 16#3445, 16#3446, 16#3530, 16#3531, 16#3532, 16#3533, 
      16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3541, 
      16#3542, 16#3543, 16#3544, 16#3545, 16#3546, 16#3630, 16#3631, 
      16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 
      16#3639, 16#3641, 16#3642, 16#3643, 16#3644, 16#3645, 16#3646, 
      16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 
      16#3737, 16#3738, 16#3739, 16#3741, 16#3742, 16#3743, 16#3744, 
      16#3745, 16#3746, 16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 
      16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3841, 16#3842, 
      16#3843, 16#3844, 16#3845, 16#3846, 16#3930, 16#3931, 16#3932, 
      16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 
      16#3941, 16#3942, 16#3943, 16#3944, 16#3945, 16#3946, 16#4130, 
      16#4131, 16#4132, 16#4133, 16#4134, 16#4135, 16#4136, 16#4137, 
      16#4138, 16#4139, 16#4141, 16#4142, 16#4143, 16#4144, 16#4145, 
      16#4146, 16#4230, 16#4231, 16#4232, 16#4233, 16#4234, 16#4235, 
      16#4236, 16#4237, 16#4238, 16#4239, 16#4241, 16#4242, 16#4243, 
      16#4244, 16#4245, 16#4246, 16#4330, 16#4331, 16#4332, 16#4333, 
      16#4334, 16#4335, 16#4336, 16#4337, 16#4338, 16#4339, 16#4341, 
      16#4342, 16#4343, 16#4344, 16#4345, 16#4346, 16#4430, 16#4431, 
      16#4432, 16#4433, 16#4434, 16#4435, 16#4436, 16#4437, 16#4438, 
      16#4439, 16#4441, 16#4442, 16#4443, 16#4444, 16#4445, 16#4446, 
      16#4530, 16#4531, 16#4532, 16#4533, 16#4534, 16#4535, 16#4536, 
      16#4537, 16#4538, 16#4539, 16#4541, 16#4542, 16#4543, 16#4544, 
      16#4545, 16#4546, 16#4630, 16#4631, 16#4632, 16#4633, 16#4634, 
      16#4635, 16#4636, 16#4637, 16#4638, 16#4639, 16#4641, 16#4642, 
      16#4643, 16#4644, 16#4645, 16#4646}). 

Thực hiện 90MB/s trên máy tính xách tay của tôi i5 CPU M 520 @ 2.40GHz khi thử nghiệm trên khối 10MB. Nhưng tối ưu hóa đã được đưa đến cùng cực ở đó. Nó cũng có thể làm 97MB nếu sử dụng 16bit tra cứu nhưng nó là điên và quá dài để gửi ở đây.

4

Bạn có thể làm: [hd (erlang: integer_to_list (Nibble, 16)) || < < Nibble: 4 >> < = Binary].

Điều này sẽ trả về cho bạn một danh sách (chuỗi) chứa các chữ số thập phân của nhị phân. Trong khi tôi nghi ngờ hiệu quả của hoạt động này sẽ có ảnh hưởng đến thời gian chạy của hệ thống của bạn, bạn cũng có thể có chức năng bin_to_hex trả về một iolist đơn giản hơn để xây dựng và sẽ được làm phẳng khi đầu ra. Các chức năng sau đây trả về một iolist với ví dụ định dạng mà bạn đã đưa:

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), 
     " >>" ]. 

Đó là một chút xấu xí, nhưng chạy qua nhị phân một lần và không đi qua danh sách đầu ra (nếu không tôi đã sử dụng chuỗi: tham gia vào có được các chuỗi "," xen kẽ). Nếu chức năng này không phải là vòng lặp bên trong của một số quy trình (tôi có một thời gian khó tin rằng chức năng này sẽ là nút cổ chai của bạn), thì có lẽ bạn nên sử dụng mã số ít hiệu quả hơn, nhưng rõ ràng hơn như:

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)]. 
0
bin_to_hex_list(Bin) when is_binary(Bin) -> 
    lists:flatten([integer_to_list(X,16) || <<X>> <= Bin]). 
+2

này không làm bất cứ zero padding, như vậy kết quả không chính xác. Nếu 4 bit đầu tiên của một byte là 0 thì nó sẽ chỉ tạo ra một chữ số cho byte đó khi hai được yêu cầu. –

6

Việc cải thiện @hairyhum

này sẽ chăm sóc của zero miếng đệm không << <<Y>> ||<<X:4>> <= Id, Y <- integer_to_list(X,16)>>

ngược chuyển đổi <<<<Z>> || <<X:8,Y:8>> <= Id,Z <- [binary_to_integer(<<X,Y>>,16)]>>, %%hex to binary

2

Điều này không thấy bất kỳ hành động nào trong một thời gian, nhưng tất cả các giải pháp trước đây dường như quá phức tạp. Đây là những gì, đối với tôi, dường như đơn giản hơn nhiều:

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

Nếu bạn thích nó mở rộng một chút:

[begin 
    if 
     N < 10 -> 
      48 + N; % 48 = $0 
     true -> 
      87 + N % 87 = ($a - 10) 
    end 
end || <<N:4>> <= Bin] 
1

Dưới đây là một phiên bản ngắn và nhanh chóng mà tôi sử dụng:

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. 
1

nếu bạn muốn tạo chuỗi nhị phân thay vì xóa chuỗi danh sách mặc định, bạn có thể sử dụng cú pháp hiểu nhị phân, giống như những gì tôi đã làm trên mã tạo sha1 của mình:

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

giống như trong python binascii.b2a_hex:

>>> binascii.b2a_hex(sha.new('hello world').digest()) 
'2aae6c35c94fcfb415dbe95f408b9ce91ee846ed' 
Các vấn đề liên quan