【问题标题】:Erlang error with binary data二进制数据的 Erlang 错误
【发布时间】:2012-10-06 18:56:28
【问题描述】:

我刚开始使用 Erlang,遇到了一个我无法解决的问题:

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

下面是代码(我用不同的方式重写了很多次):

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。

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

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

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

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

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

**

TT = >, SS = > %%

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

TT = >, SS = >

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.

MdP

【问题讨论】:

  • 请不要在代码中的 cmets 中隐藏您的问题...
  • &lt;&lt;"www.404pagenotfound.com"&gt;&gt; 的输出不应该是&lt;&lt;3,"www",15,"404pagenotfound",3,"com"&gt;&gt;吗?
  • 谢谢@rvirding,是的,这是一个类型,我更正了原帖。
  • @user1750572 是的,您是对的,但是由于您编写的内容,目前的代码仍然会崩溃。

标签: dns binary erlang


【解决方案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 字节,并修剪任何额外的尾随点。

【讨论】:

  • 您好,谢谢您的回复,但正如您在代码中看到的那样,我已经考虑过:
  • 如你所见,我考虑过:[Chunk|RestList]] = Res and thx for the NUL byte advice...
  • 你确定RestList 周围的那组额外的[] 吗?如果没有 global 选项,RestList 应该只是剩余的父域标签。我正在尝试复制它,但我安装的 Erlang 没有 binary 模块。
  • 嗨@Alnitak,是的,没关系,在这个来源中,问题与第6行二进制数据使用的长度方法有关:如果长度(RestList)> 0。我修改了代码如下所示,还有另一个令人讨厌的问题。 :(domainbyte(Bin) -&gt; if byte_size(Bin) &gt; 0 -&gt; Res = binary:split(Bin, &lt;&lt;"."&gt;&gt;), if length(Res) &gt; 1 -&gt; [Chunk|[RestList]] = Res, ChunkSize = byte_size(Chunk), Rest = domainbyte(RestList), &lt;&lt;ChunkSize/binary,Chunk,Rest&gt;&gt;; true -&gt; [Chunk] = Res, ChunkSize = byte_size(Chunk), &lt;&lt;ChunkSize/binary,Chunk&gt;&gt; end end.
  • 您不应该让label/1 函数同时在块列表和每个块上工作。尽管它允许您拥有二进制文件和列表的嵌套列表。
【解决方案2】:

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

<< <<ChunkSize>>/binary, Chunk/binary, Rest/binary>>
% and
<< <<ChunkSize>>/binary, Chunk/binary>>

【讨论】:

  • 谢谢@halfelf,刚刚想通了...:D
  • 谢谢。如果我的回答对您有帮助,如果您接受,我将不胜感激。
【解决方案3】:

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

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 的空段。如果应丢弃这些,则需要将选项 trim 添加到 binary: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.

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

我现在够了。

【讨论】:

  • 非常感谢,如前所述,我只是一个 erlang 新手,我完全错过了理解功能......无论如何,我的第二个实现呢? Altought不好,对我来说似乎是正确的,那么,为什么我会出错?我正在努力学习,这种错误令人沮丧......谢谢。
  • @user1750572 对列表和二进制的理解有点深奥,尽管在某些情况下它们可以产生非常简洁的代码。
  • @user1750572 刚刚添加了一些关于编写函数的替代方法。
猜你喜欢
  • 1970-01-01
  • 2018-02-22
  • 2015-06-01
  • 2012-06-25
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 2021-12-26
  • 2014-08-27
相关资源
最近更新 更多