如何使用pyparsing解析分数表达式?

Xav*_*ian 5 python dsl parsing pyparsing fractions

到目前为止,我们刚刚开始尝试使用轮胎pyparsing,但是我们无法帮助我们解析分数字符串以将它们转换为数字数据类型.

例如,如果数据库表中的列值包含字符串:

1 1/2

我们想要一些方法将它转换为数字python等价物:

1.5

我们想制作一个解析器,它不关心分数中的数字是整数还是实数.例如,我们想:

1.0 1.0/2.0

...仍然翻译为:

1.5

从本质上讲,我们希望解析器在概念上执行以下操作:

"1 1/2"= 1 + 0.5 = 1.5

以下示例代码似乎让我们接近......

http://pyparsing.wikispaces.com/file/view/parsePythonValue.py

......但还不够接近,无法取得进展.我们制作小数处理程序的所有测试只返回表达式(1)的第一部分.提示?提示?及时的智慧?:)

Pau*_*McG 6

既然你引用了一些测试,听起来你至少已经对这个问题进行了尝试.我假设你已经定义了一个数字,可以是整数或实数 - 无关紧要,你将所有东西转换为浮点数 - 以及两个数字的一​​小部分,可能是这样的:

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)
Run Code Online (Sandbox Code Playgroud)

(注意使用解析动作,它在解析时执行浮点转换和小数除法.我更喜欢在解析时执行此操作,当我知道某些内容是数字或分数或其他内容时,而不是稍后返回并筛选通过一堆碎片字符串,尝试重新创建解析器已经完成的识别逻辑.)

以下是我为您的问题编写的测试用例,由整数,分数,整数和分数组成,使用整数和实数:

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)
Run Code Online (Sandbox Code Playgroud)

最后一步是如何定义分数表达式,该分数表达式可以是单个数字,分数,或单个数字和分数.

由于pyparsing是从左到右,它不会像regexen那样进行同样的回溯.所以这个表达不会那么好用:

fractExpr = Optional(number) + Optional(fraction)
Run Code Online (Sandbox Code Playgroud)

要将可能来自数字和小数部分的数值相加,请添加此解析操作:

fractExpr.setParseAction(lambda t: sum(t))
Run Code Online (Sandbox Code Playgroud)

我们的测试打印出来:

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]
Run Code Online (Sandbox Code Playgroud)

对于测试的情况下1/2,只包含本身的一小部分,领先的分子中的匹配Optional(number)项,但留给我们只是用"/ 2",这匹配Optional(fraction)-幸运的是,因为第二项是可选的,这个"通行证" ,但它并没有真正做我们想要的.

我们需要让fractExpr变得更聪明,并且首先看一个单独的分数,因为在单个数字和分数的前导分子之间存在这种潜在的混淆.最简单的方法是使fractExpr读取:

fractExpr = fraction | number + Optional(fraction)
Run Code Online (Sandbox Code Playgroud)

现在有了这个改变,我们的测试会更好:

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]
Run Code Online (Sandbox Code Playgroud)

有一些经典陷阱与pyparsing,这是其中之一.请记住,pyparsing只会告诉你它的前瞻,否则它只是直接从左到右的解析.