Python 解析二进制数字序列

Python 解析二进制数字序列,python,parsing,grammar,pyparsing,parsimonious,Python,Parsing,Grammar,Pyparsing,Parsimonious,如何在python中解析二进制数字序列。 下面是我正在尝试做的一个例子 例如,我有一个二进制数字序列 sequence = '1110110100110111011011110101100101100' 我需要解析它并提取数据 假设上述序列包含开始、id、数据和结束字段 开始是一个2位字段,id是一个8位字段,数据字段可以从1到8192位不等,结束是一个4位字段 解析后,我希望输出如下: result = {start : 11, id : 10110100,

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

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

sequence =  '1110110100110111011011110101100101100'
我需要解析它并提取数据

假设上述序列包含开始、id、数据和结束字段

开始是一个2位字段,id是一个8位字段,数据字段可以从1到8192位不等,结束是一个4位字段

解析后,我希望输出如下:

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

start = ~"[01]{2}"
id = ~"[01]{8}"
data = ~"[01]{1,8192}"
end = ~"[01]{4}"
"""
我正在我的一个应用程序中使用它。 我可以使用正则表达式解析序列,但问题是正则表达式必须由用户编写。作为替代,我使用BNF语法,因为语法更具可读性

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

我在python可用的
consimonious
中编写的语法如下:

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

start = ~"[01]{2}"
id = ~"[01]{8}"
data = ~"[01]{1,8192}"
end = ~"[01]{4}"
"""
由于数据字段长度可变,并且解析器贪婪,因此上述序列无法与上述语法匹配。解析器将结束字段位带入数据字段

我只是把我的问题简化为上面的例子

让我来描述整个问题。有3种数据包(我们称它们为令牌、握手和数据包)。令牌和握手数据包的长度固定,数据包的长度可变。(上面所示的示例是数据分组的示例)

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

令牌包语法示例:

start - 2 bits, id - 8 bits, address - 7bits, end - 4bits
111011010011011101100
start - 2 bits, id - 8bits, end - 4 bits
11101101001100
握手包语法示例:

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种不同的数据包类型需要解析的情况下,我们能让切片方法工作吗

解决这个问题的最好办法是什么


提前感谢,

这样就可以了,只需使用切片即可完成此工作:

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

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

这样就可以了,只需为此作业使用切片:

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

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

假定只有一个可变长度字段,因此您可以通过定义距序列开始的距离和距序列结束的距离来实现这一点,例如

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'}

假设只有一个可变长度字段,因此您可以通过定义距序列起点的距离和距序列终点的距离来实现这一点,例如

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'}

既然您在标记中提到了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]

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

既然您在标记中提到了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]

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

任何类型的解析器对此都可能有点过头了。您有固定宽度的字段。@Karoly我已经编辑了问题。可以有不同类型的数据包。所以我想用语法的方法来解决这个问题。任何类型的解析器都可能是一种过火的方法。您有固定宽度的字段。@Karoly我已经编辑了问题。可以有不同类型的数据包。所以我想用语法的方法来解决这个问题。谢谢你的回答。但是,很抱歉,我没有在问题中提到,即使字段也不是固定的。用户将以字段长度作为语法输入字段名。还有多个字段可以具有可变长度。@user2109788:多个可变长度字段表示语法不明确。扩展你的问题。我已经扩展了这个问题。在我的问题中,只有一个可变长度字段。我的想法很笼统,所以我在上面的评论中提到可以有更多的可变长度字段。那么现在你能帮我找到这个问题的答案吗?@user2109788-我已经读过了,但是,除非你知道或者有解析数据,否则你无法解析它,你可能有一个标题或者其他东西,因为它解释了你必须读哪种类型的数据包。谢谢你的回答。但是,很抱歉,我没有在问题中提到,即使字段也不是固定的。用户将以字段长度作为语法输入字段名。还有多个字段可以具有可变长度。@user2109788:多个可变长度字段表示语法不明确。扩展你的问题。我已经扩展了这个问题。在我的问题中,只有一个可变长度字段。我的想法很笼统,所以我在上面的评论中提到可以有更多的可变长度字段。那么现在你能帮我找到这个问题的答案吗?@user2109788-我已经读过了,但是,除非你知道或者有解析它的数据,否则你不能解析它,你可能有一个头或者什么东西,它解释了你必须读什么类型的数据包。我们可以用lambda来定义规则吗?我想在内联调用中设置规则。有可能吗?我不知道你的意思。请给出输入和输出示例。我们可以使用lambda定义规则吗?我想在内联调用中设置规则。有可能吗?我不知道你的意思。请给出输入和输出示例。