0

如何在 python 中解析二进制数字序列。以下是我正在尝试做的一个例子。

我有一个二进制数字序列,例如

sequence =  '1110110100110111011011110101100101100'

而且,我需要解析它并提取数据。

假设上面的序列包含start、id、data 和 end 字段

start 是 2 位字段,id 是 8 位字段,数据字段可以在 1 到 8192 位之间变化,end 是 4 位字段。

解析后我期望输出如下:

result = {start : 11,
          id : 10110100,
          data : 11011101101111010110010,
          end : 1100,
         }

我在我的一个应用程序中使用它。我可以使用正则表达式解析序列,但问题是正则表达式必须由用户编写。因此,作为替代方案,我使用 BNF 语法,因为语法更具可读性。

我尝试使用 python 的简约pyparsing解析器来解决这个问题。但我无法找到可变长度字段的解决方案。

我写的可用于python的语法parsimonious如下:

grammar = """sequence = start id data end

start = ~"[01]{2}"
id = ~"[01]{8}"
data = ~"[01]{1,8192}"
end = ~"[01]{4}"
"""

由于数据字段是可变长度的,并且解析器是贪婪的,所以上述序列无法与上述语法匹配。解析器将结束字段位带入数据字段。

我只是将我的问题简化为上面的示例。

让我描述一下完整的问题。有 3 种数据包(我们称它们为 Token、Handshake 和 Data 数据包)。令牌和握手包是固定长度的,数据包是可变长度的。(上面的例子是数据包的例子)

输入由连续的比特流组成。每个数据包开始由“开始”模式标记,数据包结束由“结束”模式标记。这两者都是固定的位模式。

令牌包语法示例:

start - 2 bits, id - 8 bits, address - 7bits, end - 4bits
111011010011011101100

握手包语法示例:

start - 2 bits, id - 8bits, end - 4 bits
11101101001100

顶级规则示例:

packet = tokenpacket | datapacket | handshakepacket

如果只有一种类型的数据包,那么切片将起作用。但是当我们开始解析时,我们不知道最终会匹配到哪个数据包。这就是为什么我想到使用语法的原因,因为这个问题与语言解析非常相似。

我们可以让切片方法在我们有 3 种不同的数据包类型要解析的情况下工作吗?

解决这个问题的最佳方法是什么?

提前致谢,

4

3 回答 3

2

这样就可以了,只需对这项工作使用切片:

def binParser(data):
    result = {}
    result["start"] = data[:2]
    result["id"] = data[2:8]
    result["end"] = data[-4:]
    result["data"] = data[10:-4]
    return result

您将从字符串中获得正确的数据。

于 2014-02-18T12:04:40.093 回答
2

据推测,只有一个可变长度字段,因此您可以通过定义与序列开头的距离和与结尾的距离来允许这一点,例如

rules = {'start': (None, 2), 'id': (2, 10), 
         'data': (10, -4), 'end': (-4, None)}

然后使用切片:

sequence =  '1110110100110111011011110101100101100'

result = dict((k, sequence[v[0]:v[1]]) for k, v in rules.items())

这给出了:

result == {'id': '10110100', 
           'end': '1100', 
           'data': '11011101101111010110010', 
           'start': '11'}
于 2014-02-18T12:08:37.033 回答
1

既然您在标签中提到了 pyparsing,那么我将如何使用 pyparsing 进行处理。这使用 Daniel Sanchez 的 binParser 进行后处理。

from pyparsing import Word

#Post-processing of the data.
def binParser(m):
    data = m[0]
    return {'start':data[:2],
            'id':data[2:8],
            'end':data[-4:],
            'data':data[10:-4]}
#At least 14 character for the required fields, attaching the processor
bin_sequence = Word('01',min=14).setParseAction(binParser)


sequence =  '1110110100110111011011110101100101100'
print bin_sequence.parseString(sequence)[0]

然后可以将其用作更大解析器的一部分。

于 2014-02-19T15:41:52.040 回答