如何使用Pyparsing来解析字符串,这涉及到忽略异常并移动到下一个分隔符



我有一个程序,它需要一个效果列表,然后是开始时间和结束时间。所以我有这个字符串,你可以从用户输入中获得它(它可能是错误的(,我试图解析相关信息并忽略错误信息,同时转到下一个效果,在每个"之后&";。然而,我不太确定如何使用Pyparsing库来实现这一点,我想知道是否可以完全使用该库来实现。代码中的注释表示它应该返回的内容,下面的输出是它实际返回的内容。

import pyparsing as pp
testcase = "bounce, 5, 10; shutter, 12, 14" # returns [[bounce, 5, 10], [shutter, 12, 14]]
testcase2= "bounce, 5, 10; shutter, 12, 14; low_effort, 2, 23" # returns [[bounce, 5, 10], [shutter, 12, 14], [low_effort, 2, 23]]
testcase3= "_lolw, a, 2; effect, 6;" # returns [[effect, 6, None]]
testcase4= "bounce, 1, 10; effect, 5, a; bounce, 2, 10" # returns [[bounce, 1, 10], [bounce, 2, 10]]
testcase5= ";;;effect, 10; bounce, a, 1; bounce, 3, 10" # returns [[effect, 10, None], [bounce, 3, 10]]
testcase6= "effect, b, a; 9, 10, 11; max9, 10, 11; here, 2, 3; !b, 1, 2;;;" # returns [[here, 2, 3]]
def parseKeyframes(string: str):
comma = pp.Suppress(",")
pattern = pp.Word(pp.alphas + "_") + comma + pp.Word(pp.nums) + pp.Optional(comma + pp.Word(pp.nums), default=None)
# parse pattern seperated by ";"
pattern = pattern | pp.SkipTo(pp.Literal(";"))
parsed = pp.delimitedList(pp.Group(pattern), ";")
parsed = parsed.parseString(string)
return parsed
print(parseKeyframes(testcase))
print(parseKeyframes(testcase2))
print(parseKeyframes(testcase3))
print(parseKeyframes(testcase4))
print(parseKeyframes(testcase5))
print(parseKeyframes(testcase6))

输出:

[['bounce', '5', '10'], ['shutter', '12', '14']]
[['bounce', '5', '10'], ['shutter', '12', '14'], ['low_effort', '2', '23']]
[['_lolw, a, 2'], ['effect', '6', None]]
[['bounce', '1', '10'], ['effect', '5', None]]
[[''], [''], [''], ['effect', '10', None], ['bounce, a, 1'], ['bounce', '3', '10']]
[['effect, b, a'], ['9, 10, 11'], ['max9, 10, 11'], ['here', '2', '3'], ['!b, 1, 2'], [''], ['']]

您的想法是正确的,只需要添加一些额外的术语,并抑制错误。

  1. 将'.suppress(('添加到SkippTo项,以便从输出中抑制跳过的无效文本
  2. 若要捕获部分匹配后面跟着无效文本(如'effect, 5, a'(的情况,必须添加一个FollowedBy项,以便匹配后面跟着";"或字符串的末尾
  3. 要处理字符串末尾的无效匹配,请跳到""或字符串的末尾

由于";" | end_of_string出现两次的目的非常相似,我为此创建了一个next_delim术语。这使外观更加清晰。我还定义了wordinteger术语,这使pattern对我来说更容易理解。

我认为这个稍微修改过的解析器版本会给你带来预期的结果:

comma = pp.Suppress(",")
# ';'-delimited list of  word , int [, int]
word = pp.Word(pp.alphas + "_")
integer = pp.Word(pp.nums)
pattern = (word
+ comma 
+ integer 
+ pp.Optional(comma + integer, default=None))

# parse pattern seperated by ";"
next_delim = ";" | pp.StringEnd()
skip_invalid = pp.SkipTo(next_delim).suppress()
pattern_or_skip = (pp.Group(pattern + pp.FollowedBy(next_delim))
| skip_invalid)
parser = pp.delimitedList(pattern_or_skip, delim=";")

最新更新