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.

手がかりについては、事前に Thx.

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.

MDP

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 の空のセグメントと見なします。これらを破棄する必要がある場合は、オプションtrimをに追加する必要がありますbinary:split/3また、サイズが1バイトしか占めないことにも注意してください。

@Alnitak には別の機能がありますが、一度に 1 セグメントずつバイナリを構築するため、同じことを行うバイナリ内包表記よりも効率的ではありません。

Chunk/binaryバイナリを構築するときにバイナリセグメントがある場合、これはChunk ISがバイナリであることを意味し、バイナリになるべきではないことに注意してくださいバイナリはフラットな構造です。バイト配列と考えてください。したがって、すべてがバイナリになります。というかバイナリ。

編集:私は最後にあるはずの 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かなり控えめに使用されます。

今のところ私からは十分です。

于 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

バイナリの連結は次のように記述します。

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