Erlang:在二进制流中解组可变长度数据字段

时间:2012-02-05 10:17:30

标签: parsing binary erlang

我正在创建一个需要解析来自第三方程序的二进制TCP流的Erlang应用程序。 我可以接收的其中一种数据包的格式如下:

  

N_terms * [标志(8位),类型(8位),[可选数据]]。

我遇到的问题是可选数据是由所有可能的排列决定的 标志和类型的组合。此外,根据类型,还有与之关联的其他可选数据。

如果我用命令式语言编写解析器,我只需读取2个字段,然后有一系列if(...)语句,我将读取一个值并增加我在流中的位置。在Erlang中,我最初的天真假设是我会有2 ^ N个函数子句来匹配流上的字节语法,其中N是标志的总数+所有带有附加可选数据的类型。

就目前而言,我至少有3个标志和1个类型,其中包含我必须实现的可选数据,这意味着我将在流上匹配16个不同的函数子句。

在Erlang中必须有更好的,惯用的方法 - 我缺少什么?

编辑: 我应该澄清我事先不知道条款的数量。

2 个答案:

答案 0 :(得分:4)

一种解决方案是采取

 <<Flag:8/integer, Type:8/integer, Rest/binary>>

然后编写一个函数decode(Flag, Type),它返回Rest将包含的描述。现在,该描述可以传递给Rest的解码器,然后可以使用给出的描述来正确地解析它。一个简单的解决方案是将描述放入列表中,每当您从流中解码某些内容时,您都可以使用该描述列表来检查它是否有效。也就是说,描述就像你的构造一样。

对于指针移动,很容易。如果您有Binary并对其进行解码

<<Take:N/binary, Next/binary>> = Binary,

接下来是您正在搜索的引擎盖下移动的指针。所以你可以将你的二进制文件分成几部分,以获得下一部分的工作。

答案 1 :(得分:1)

我会解析它:

parse_term(Acc,0,<<>>) ->  {ok,Acc};
parse_term(_,0,_)      ->  {error,garbage};
parse_term(Acc,N,<<Flag:8/integer,Type:8/integer,Rest/binary>>) ->
 {Optional,Rest1} = extract_optional(Flag,Type,Rest),   
 parse_term([{Flag,Type,Optional}|Acc],N-1,Rest1>>).

parse_stream(<<NTerms/integer,Rest/binary>>)->
    parse_term([],NTerms,Rest).