gpt4 book ai didi

python - 从多个标记的字符串构建 pyparsing.Dict - 第二部分

转载 作者:太空宇宙 更新时间:2023-11-03 14:00:26 25 4
gpt4 key购买 nike

由于这个论坛的反馈,我已经取得了一些进展(感谢论坛!)。pyparsing.Dict 对象字典正在填充,但当它找到十进制数字时,它会默默地失败。

给定:

import pyparsing as pp

lines = '''\
(rate multiple)
(region "mountainous")
(elev 21439)
(alteleva +21439)
(altelevb -21439)
(coorda 23899.747)
(coordb +23899.747)
(coordc -23899.747)
(coordd 853.324e21)
(coorde +853.324e21)
(coordf -853.324e21)
(coordg 987.88e+09)
(coordh +987.88e+09)
(coordi -987.88e+09)
(coordj 122.45e-04)
(coordk +122.45e-04)
(coordl -122.45e-04)
'''

leftParen = pp.Literal('(')
rightParen = pp.Literal(')')
colon = pp.Literal(':')
decimalpoint = pp.Literal('.')
doublequote = pp.Literal('"')
plusorminus = pp.Literal('+') | pp.Literal('-')
exp = pp.CaselessLiteral('E')

v_string = pp.Word(pp.alphanums)
v_quoted_string = pp.Combine( doublequote + v_string + doublequote)
v_number = pp.Regex(r'[+-]?(?P<float1>\d+)(?P<float2>\.\d+)?(?P<float3>[Ee][+-]?\d+)?')

keyy = v_string
valu = v_string | v_quoted_string | v_number

item = pp.Group( pp.Literal('(').suppress() + keyy + valu + pp.Literal(')').suppress() )
items = pp.ZeroOrMore( item)
dict = pp.Dict( items)

print "dict yields: ", dict.parseString( lines).dump()

产量

- alteleva: '+21439',
- altelevb: '-21439',
- elev: '21439',
- rate: 'multiple',
- region: '"mountainous"'

更改标记的顺序证明脚本在遇到第一个十进制数时会默默失败,这意味着 pp.Regex 语句存在一些微妙的错误,但我确实无法发现它。

TIA,

代码战士

最佳答案

你的问题实际上出在这个表达式上:

valu = v_string | v_quoted_string | v_number

因为v_string被定义为非常广泛匹配的表达式:

v_string = pp.Word(pp.alphanums)

并且因为它是 valu 中的第一个表达式,它将屏蔽 v_numbers以数字开头的。这是因为“|”运算符(operator)产生 pp.MatchFirst对象,因此第一个匹配的表达式(从左到右阅读)将确定使用哪个替代方案。您可以转换为使用“^”运算符,它会生成 pp.Or对象 - Or类将尝试评估所有替代方案,然后选择最长的匹配项。但是,请注意使用 Or会带来性能损失,因为即使没有机会混淆,也会测试更多的表达式来进行匹配。在您的情况下,您只需重新排序表达式,将最不具体的匹配表达式放在最后:

valu = v_quoted_string | v_number | v_string

现在,值将首先尝试解析为带引号的字符串,然后解析为数字,然后仅当这些特定类型中的任何一个都没有匹配时,如非常通用的类型 v_string .

其他一些评论:

我个人更喜欢解析带引号的字符串,只获取引号内的内容(这是一个字符串,我已经知道了!)。当显示解析的字符串没有任何引号时,转储解析结果时,旧版本的 pyparsing 曾经会出现一些困惑。但现在我使用 repr() 来显示解析的值,调用 dump() 时字符串会显示在引号中,但值本身不包括引号。当它在程序的其他地方使用时,例如保存到数据库或 CSV,我不需要引号,我只需要字符串内容。 QuotedString默认情况下,类会为我处理这个问题。或者使用pp.quotedString().addParseAction(pp.removeQuotes) .

最近的 pyparsing 版本引入了 pyparsing_common命名空间类,包含许多有用的预定义表达式。有几个用于解析不同数字类型(整数、有符号整数、实数等)的表达式,以及几个总括表达式: number将解析任何数字类型,并生成相应类型的值( real 将给出 float , integer 将给出 int 等); fnumber将解析各种数字,但将它们全部返回为 float 。我已经替换了你的v_number表达式仅 pp.pyparsing_common.number() ,这还允许我删除仅用于构建 v_number 定义的其他几个部分表达式。表达式,如 decimalpoint , plusorminusexp 。您可以在 pyparsing_common 中查看有关表达式的更多信息。在在线文档:https://pythonhosted.org/pyparsing/

Pyparsing 在处理像 "(" + pp.Word(pp.alphas) + valu + ")" 这样的表达式中的文字字符串时的默认行为就是自动将字面量“(”和“)”项转换为 pp.Literal对象。这可以防止意外丢失已解析的数据,但在标点符号的情况下,最终会在解析结果中出现许多困惑且无用的额外字符串。在你的解析器中,你可以通过调用 pp.ParserElement.inlineLiteralsUsing 来替换 pyparsing 的默认值。并通过 pp.Suppress类:

pp.ParserElement.inlineLiteralsUsing(pp.Suppress)

现在您可以编写如下表达式:

item  = pp.Group('(' + keyy + valu + ')')

并且分组括号将从解析结果中隐藏。

进行这些更改后,您的解析器现在可以简化为:

import pyparsing as pp

# override pyparsing default to suppress literal strings in expressions
pp.ParserElement.inlineLiteralsUsing(pp.Suppress)

v_string = pp.Word(pp.alphanums)
v_quoted_string = pp.QuotedString('"')
v_number = pp.pyparsing_common.number()

keyy = v_string
# define valu using least specific expressions last
valu = v_quoted_string | v_number | v_string

item = pp.Group('(' + keyy + valu + ')')
items = pp.ZeroOrMore( item)
dict_expr = pp.Dict( items)

print ("dict yields: ", dict_expr.parseString( lines).dump())

对于您的测试输入,给出:

dict yields:  [['rate', 'multiple'], ['region', 'mountainous'], ['elev', 21439], 
['alteleva', 21439], ['altelevb', -21439], ['coorda', 23899.747], ['coordb',
23899.747], ['coordc', -23899.747], ['coordd', 8.53324e+23], ['coorde',
8.53324e+23], ['coordf', -8.53324e+23], ['coordg', 987880000000.0], ['coordh',
987880000000.0], ['coordi', -987880000000.0], ['coordj', 0.012245], ['coordk',
0.012245], ['coordl', -0.012245]]
- alteleva: 21439
- altelevb: -21439
- coorda: 23899.747
- coordb: 23899.747
- coordc: -23899.747
- coordd: 8.53324e+23
- coorde: 8.53324e+23
- coordf: -8.53324e+23
- coordg: 987880000000.0
- coordh: 987880000000.0
- coordi: -987880000000.0
- coordj: 0.012245
- coordk: 0.012245
- coordl: -0.012245
- elev: 21439
- rate: 'multiple'
- region: 'mountainous'

关于python - 从多个标记的字符串构建 pyparsing.Dict - 第二部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49284998/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com