[英]parsing nested structures with pyparsing
我正在尝试解析生物序列中位置的特定语法。 这些职位可以有以下形式:
12 -- a simple position in the sequence
12+34 -- a complex position as a base (12) and offset(+34)
12_56 -- a range, from 12 to 56
12+34_56-78 -- a range as a start to end, where either or both may be simple or complex
我希望将这些解析为dicts,大致如下:
12 -> { 'start': { 'base': 12, 'offset': 0 }, 'end': None }
12+34 -> { 'start': { 'base': 12, 'offset': 34 }, 'end': None }
12_56 -> { 'start': { 'base': 12, 'offset': 0 },
'end': { 'base': 56, 'offset': 0 } }
12+34_56-78 -> { 'start': { 'base': 12, 'offset': 0 },
'end': { 'base': 56, 'offset': -78 } }
我用pyparsing做了几次刺伤。 这是一个:
from pyparsing import *
integer = Word(nums)
signed_integer = Word('+-', nums)
underscore = Suppress('_')
position = integer.setResultsName('base') + Or(signed_integer,Empty).setResultsName('offset')
interval = position.setResultsName('start') + Or(underscore + position,Empty).setResultsName('end')
结果接近我想要的结果:
In [20]: hgvspyparsing.interval.parseString('12-34_56+78').asDict()
Out[20]:
{'base': '56',
'end': (['56', '+78'], {'base': [('56', 0)], 'offset': [((['+78'], {}), 1)]}),
'offset': (['+78'], {}),
'start': (['12', '-34'], {'base': [('12', 0)], 'offset': [((['-34'], {}), 1)]})}
两个问题:
asDict()仅适用于根parseResult。 有没有办法哄骗pyparsing返回一个嵌套的dict(只有那个)?
如何获得范围结束和位置偏移的可选性? 位置规则中的Or()不会削减它。 (我在范围的末尾尝试了类似的方法。)理想情况下,我会将所有位置视为最复杂形式的特殊情况(即{start:{base,end},end:{base,end}}),更简单的情况下使用0或None。)
谢谢!
一些一般的pyparsing技巧:
Or(expr, empty)
最好写为Optional(expr)
。 此外,您的Or表达式尝试使用类Empty创建Or,您可能打算为第二个参数写入Empty()
或empty
。
expr.setResultsName("name")
现在可以写为expr("name")
如果要将结构应用于结果,请使用“ Group
。
使用dump()
而不是asDict()
来更好地查看已解析结果的结构。
这是我如何建立你的表达式:
from pyparsing import Word, nums, oneOf, Combine, Group, Optional
integer = Word(nums)
sign = oneOf("+ -")
signedInteger = Combine(sign + integer)
integerExpr = Group(integer("base") + Optional(signedInteger, default="0")("offset"))
integerRange = integerExpr("start") + Optional('_' + integerExpr("end"))
tests = """\
12
12+34
12_56
12+34_56-78""".splitlines()
for t in tests:
result = integerRange.parseString(t)
print t
print result.dump()
print result.asDict()
print result.start.base, result.start.offset
if result.end:
print result.end.base, result.end.offset
print
打印:
12
[['12', '0']]
- start: ['12', '0']
- base: 12
- offset: 0
{'start': (['12', '0'], {'base': [('12', 0)], 'offset': [('0', 1)]})}
12 0
12+34
[['12', '+34']]
- start: ['12', '+34']
- base: 12
- offset: +34
{'start': (['12', '+34'], {'base': [('12', 0)], 'offset': [('+34', 1)]})}
12 +34
12_56
[['12', '0'], '_', ['56', '0']]
- end: ['56', '0']
- base: 56
- offset: 0
- start: ['12', '0']
- base: 12
- offset: 0
{'start': (['12', '0'], {'base': [('12', 0)], 'offset': [('0', 1)]}), 'end': (['56', '0'], {'base': [('56', 0)], 'offset': [('0', 1)]})}
12 0
56 0
12+34_56-78
[['12', '+34'], '_', ['56', '-78']]
- end: ['56', '-78']
- base: 56
- offset: -78
- start: ['12', '+34']
- base: 12
- offset: +34
{'start': (['12', '+34'], {'base': [('12', 0)], 'offset': [('+34', 1)]}), 'end': (['56', '-78'], {'base': [('56', 0)], 'offset': [('-78', 1)]})}
12 +34
56 -78
实际语法是否比您的示例更复杂? 因为解析可以在纯Python中相当容易地完成:
bases = ["12", "12+34", "12_56", "12+34", "12+34_56-78"]
def parse_base(base_string):
def parse_single(s):
if '-' in s:
offset_start = s.find("-")
base, offset = int(s[:offset_start]), int(s[offset_start:])
elif '+' in s:
offset_start = s.find("+")
base, offset = int(s[:offset_start]), int(s[offset_start:])
else:
base = int(s)
offset = 0
return {'base': base, 'offset': offset}
range_split = base_string.split('_')
if len(range_split) == 1:
start = range_split[0]
return {'start': parse_single(start), 'end': None}
elif len(range_split) == 2:
start, end = range_split
return {'start': parse_single(start),
'end': parse_single(end)}
输出:
for b in bases:
print(parse_base(b))
{'start': {'base': 12, 'offset': 0}, 'end': None}
{'start': {'base': 12, 'offset': 34}, 'end': None}
{'start': {'base': 12, 'offset': 0}, 'end': {'base': 56, 'offset': 0}}
{'start': {'base': 12, 'offset': 34}, 'end': None}
{'start': {'base': 12, 'offset': 34}, 'end': {'base': 56, 'offset': -78}}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.