pyparsing 范围解析整数字节表示

pyparsing range parsing over integer byte representation

我想知道 pyparsing 是否可以解析和检测(以一种简单的方式)由几个字节表示的一系列整数。这是一段代码,我可以用它来解析整数部分,然后用它做一些事情(只需打印它之后的任何内容):

from pyparsing import *
import struct
import re

min = 0x06A1D58C  # 111_269_260
max = 0x14B4CB1C  # 347_392_796

line_a = b'3F\x09\x21\xe4\xc0KBHDVC'

ParserElement.setDefaultWhitespaceChars("")
expr = Suppress('3F') + Regex(re.compile(r'.{4}', re.DOTALL)).setResultsName('id') + Word(
    srange('[A-Z]')).setResultsName('code')
expr.parseWithTabs()
try:
    result = expr.parseString(line_a.decode('latin-1'), parseAll=False)
    print(result.get('id').encode('latin-1'))
    id= struct.unpack('!I', result.get('id').encode('latin-1'))[0]
    code = result.get('code')
    if min <= id <= max:
        print(id, code)
except ParseException as e:
    print(e.explain(e))

输出:

b'\t!\xe4\xc0'
153216192 KBHDVC

现在我想要的是能够有一个表达式来指定整数形式的范围以及后面的内容。这样就可以根据这个整数指定几种语法。

这可能吗?还是我必须将其保留在解析之外作为 post 处理?

如果您希望此转换和验证作为表达式定义的一部分发生,您可以添加 parse-time 回调,或 解析操作:

binary_bytes = Regex(re.compile(r'.{4}', re.DOTALL))
def unpack(tokens):
    return struct.unpack('!I', tokens[0].encode('latin-1'))[0]
binary_bytes.addParseAction(unpack)

解析操作可以采用解析的标记和 return 转换或增加的值。

您还可以使用像这样的解析操作来实现类似范围检查的过滤器:

def in_range(tokens):
    if not (min <= tokens[0] <= max):
        raise ParseException()

这种过滤器或验证器很常见,您可以使用 addCondition 来定义它:

binary_bytes.addCondition(lambda tokens: min <= tokens[0] <= max)

我重新格式化并重新打包了您的示例,如下所示:

def make_range_condition(minval, maxval):
    in_range = lambda x, minval=minval, maxval=maxval: minval <= x <= maxval
    return lambda t: in_range(t[0])

binary_bytes = Regex(re.compile(r'.{4}', re.DOTALL))
binary_bytes.addParseAction(lambda tokens: struct.unpack('!I', tokens[0].encode('latin-1'))[0])
binary_bytes.addCondition(make_range_condition(min, max))

ParserElement.setDefaultWhitespaceChars("")
expr = (Suppress('3F')
        + binary_bytes('id')
        + Word(srange('[A-Z]'))('code')
        )
expr.parseWithTabs()

try:
    result = expr.parseString(line_a.decode('latin-1'), parseAll=False)
    print(result.dump())
except ParseException as e:
    print(e.explain(e))

dump() 给出了这个输出:

[153216192, 'KBHDVC']
- code: 'KBHDVC'
- id: 153216192