2

我刚开始在 Erlang 上的道路,我遇到了一个我无法解决的问题:

我写了一个方法来将域表示为二进制字符串,即 <<"www.404pagenotfound.com">> 并将其转换为 DNS 协议所需的域格式,因此:<<3,"www",15 "pagenotfound",3,"com">>.

在下面的代码中(我以不同的方式重写了很多次):

domainbyte(Bin) ->
    if byte_size(Bin) > 0 ->
        Res =  binary:split(Bin, <<".">>),
        [Chunk|[RestList]] = Res, 
        ChunkSize = byte_size(Chunk),   
        if length(RestList) > 0 -> 
            Rest = domainbyte(RestList),  %% <- Got "bad argument" here!
            <<ChunkSize/binary,Chunk,Rest>>;
        true ->
            <<ChunkSize/binary,Chunk>>
        end
    end.

提前谢谢任何线索。

PS。

感谢评论,我在上面的代码中发现了错误:

if length(RestList) > 0 -> %% here RestList is binary data so length throw "bad argument" error.

我以这种方式重写了该方法,但仍然没有运气:

**注意:我能够修复以下代码,问题是如果你有一个二进制块并且你想在另一个二进制字符串中使用它,你必须在它上面指定 /binary:这对我来说并不明显。

即:考虑这个小代码片段:

**

TT = <<"com">>, SS = <<3, TT, 0>> %% <- 你得到错误:参数错误

** 必须以这种方式修复:**

TT = <<"com">>, SS = <<3, TT/二进制, 0>>

domainbyte(Bin) ->
    if byte_size(Bin) > 0 ->
        Res =  binary:split(Bin, <<".">>),
                if length(Res) > 1 -> 
                    [Chunk|[RestList]] = Res, 
                    ChunkSize = byte_size(Chunk),
                    Rest = domainbyte(RestList),
                    <<ChunkSize,Chunk,Rest>>;
                true -> 
                    [Chunk] = Res,
                    ChunkSize = byte_size(Chunk), 
                    <<ChunkSize,Chunk>>
                end
    end.

甲基苯丙胺

4

3 回答 3

2

我认为最简单的解决方案是使用二进制理解来定义函数:

domainbyte(Bin) ->
    Chunks = binary:split(Bin, <<".">>, [global]),      %A list of all the chunks
    << <<byte_size(C),C/binary>> || C <- Chunks >>.     %Build output binary

将输出二进制文件构建为单独函数中的段列表然后将它们放在一个iolist_to_binary/1. 请注意,如果一个 '.' 出现在二进制文件的最外层,则此代码会将其视为长度为 0 的空段。如果应丢弃这些,则需要将选项添加trimbinary:split/3. 另请注意,大小将仅占用一个字节。

@Alnitak 具有单独的功能,但一次构建二进制一个段,因此它并不比执行相同操作的二进制理解更有效。

注意,如果你Chunk/binary在构建二进制文件时有一个二进制段,这意味着它Chunk 一个二进制文件,而不是它应该成为一个二进制文件。二进制是平面结构,想想字节数组,所以一切都变成了二进制。或者更确切地说是二进制文件。

编辑:虽然我看到我错过了应该在最后的 0 。这留给读者作为练习。

编辑:教学模式下,除了构建二进制文件之外,编写好的Erlang代码的关键是理解模式匹配。你用了一点,但可以做得更多:

domainbyte(Bin) ->
    case binary:split(Bin, <<".">>) of
        [Chunk,Rest] ->                       %There was a '.'
            RestBin = domainbyte(Rest),
            Size = byte_size(Chunk),
            <<Size,Chunk/binary,RestBin/binary>>;
        [Chunk] ->                            %This was the last chunk
            Size = byte_size(Chunk),
            <<Size,Chunk/binary,0>>           %Add terminating 0
end.

这基本上与您的代码相同,但我们使用模式匹配来选择一个子句,而不仅仅是分离一个已知的结构。模式匹配是控制的基本方法,不仅在caseas 中,而且在函数和receive中。这导致if使用非常谨慎。

我现在就够了。

于 2012-10-16T20:25:47.980 回答
1

我对 Erlang 有点生疏,但我认为你的问题是RestList来自binary:split.

domainbyte因此,当您以错误的格式将其以递归方式退回时。

另外 - 不要忘记终止 NUL 字节来表示根标签!

FWIW,这是我的工作版本:

label([]) ->
    << 0 >>;

label([H|T]) ->
    D = label(H),
    P = label(T),
    << D/binary, P/binary>>;

label(A) ->
    L = byte_size(A),
    << <<L>>/binary, A/binary>>.

domainbyte(A) ->
    Res = binary:split(A, <<".">>, [global, trim]),
    label(Res).

它正确地添加了一个尾随 NUL 字节,并修剪任何额外的尾随点。

于 2012-10-16T16:02:05.230 回答
0

二进制文件的 concat 应该这样写:

<< <<ChunkSize>>/binary, Chunk/binary, Rest/binary>>
% and
<< <<ChunkSize>>/binary, Chunk/binary>>
于 2012-10-16T16:55:33.107 回答