由于您引用了一些测试,这听起来像您至少已经采取了刺探问题。我假设你已经定义的单号,可以是整数或实 - 不要紧,要转换的一切反正浮动 - 和两个数字的一小部分,大概是这样的:
from pyparsing import Regex, Optional
number = Regex(r"\d+(\.\d*)?").setParseAction(lambda t: float(t[0]))
fraction = number("numerator") + "/" + number("denominator")
fraction.setParseAction(lambda t: t.numerator/t.denominator)
(注意使用解析动作,也做浮点转换和分数划分权在分析时的,我更喜欢这样做,而解析,当我知道东西是不是数字或分数或什么的,而不是稍后再回来并通过了一堆零散的字符串筛选,试图重新解析器已经做好了识别逻辑。)
下面是测试情况下,我的COM提出您的问题,由一个整数,分数和整数和分数,同时使用整数和实数:
tests = """\
1
1.0
1/2
1.0/2.0
1 1/2
1.0 1/2
1.0 1.0/2.0""".splitlines()
for t in tests:
print t, fractExpr.parseString(t)
的最后一步是如何定义的分数表达,可以是单个数字,分数,或单个数字和分数。
由于pyparsing是左到右,它不会做同一种回溯喜欢使用regexen做的。所以这个表达式不会工作这么好:
fractExpr = Optional(number) + Optional(fraction)
综上所述可能来自数和小数部分的数值加在一起,添加此解析动作:
fractExpr.setParseAction(lambda t: sum(t))
我们的测试结果打印出来:
1 [1.0]
1.0 [1.0]
1/2 [1.0]
1.0/2.0 [1.0]
1 1/2 [1.5]
1.0 1/2 [1.5]
1.0 1.0/2.0 [1.5]
测试用例1/2
,只包含本身的一小部分,领先的分子的Optional(number)
项匹配,但留给我们只是用“/ 2”,W HICH 不匹配Optional(fraction)
- 幸运的是,因为第二项是可选的,这个“通行证”,但它不是真正做我们想要的。
我们需要fractExpr聪明一点,有它首先寻找一个孤独的分数,因为有一个唯一的号码和分数的领先分子之间的这种潜在的混乱。要做到这一点最简单的方法就是让fractExpr阅读:
fractExpr = fraction | number + Optional(fraction)
现在有了这个变化,我们的测试中走出来更好:
1 [1.0]
1.0 [1.0]
1/2 [0.5]
1.0/2.0 [0.5]
1 1/2 [1.5]
1.0 1/2 [1.5]
1.0 1.0/2.0 [1.5]
有几个经典的陷阱与pyparsing的,这是其中之一。只要记住,pyparsing只会做你告诉它的前瞻,否则它只是直接从左到右的解析。
真棒,很好的答案,谢谢你花时间拼出来!我们得到了测试用例:1/2 [1.0],并且为什么我们一直得到1而不是0.5。它看起来像你勾画了我们的绊脚石。数据本身非常混乱,但看起来这至少可以为我们打下坚实的基础,并列举其他最常见的客户产品属性值表达式。 :) – Xavian 2010-10-12 19:28:29