带有字符串解析的递归数学运算

时间:2019-04-04 09:09:59

标签: python recursion text-parsing string-parsing

我想递归地解析输入字符串,以解决数学问题。

输入以以下形式给出:

(P1=[X=(0.6,3),Y=(0.4,-1)],P2=[X=(0.3,0),Y=(0.4,[Y1=(0.8,[X=(0.2,1),Y=(0.8,2)]),Y2=(0.2,3)]),Z=(0.3,2)],P3=[A=(1,1)])

目标是计算P1P2P3并找出谁的价值最大。

此问题的数学解决方法如下:

P1 = 0.6 * 3 + 0.4 * (-1) = 1.4
P2 = 0.3 * 0 + 0.4 * ( 0.8 * (0.2 * 1 + 0.8 * 2) + 0.2 * 3) + 0.3 * 2 = 1.416
P3 = 1 * 1 = 1

所以P2 > P1 > P3

输出应为P2

这是一个简单的问题,可能在括号内进行更多的操作。

我不知道如何用不同的定界符分割输入字符串,以及如何递归地进行输入。

我是编程和python的新手,但任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

对于刚接触编程的人来说,编写递归解析器非常雄心勃勃。编写任何解析器的最佳实践是从编写BNF(代表“ Backus-Naur Form”(Backus-Naur形式))开始,该BNF用作解析器的位规划。在编写任何代码之前,请执行此操作。编写代码和设计解析器是非常不同的思维活动-解析器设计涉及很多模式匹配,对于递归解析器而言,它涉及表达式嵌套的标识。您的BNF不必正式或严格,只要您仔细考虑各个部分如何从一个过渡到另一个。

以下是您语法的BNF:

number ::= an int or float numeric literal
identifier ::= an alphabetic character, followed by zero or more digits

factor_part ::= number | terms
factors ::= '(' factor_part (',' factor_part)... ')'

ident_factor ::= identifier '=' factors
terms ::= '[' ident_factor (',' ident_factor)... ']'

ident_term ::= identifier '=' terms
parser ::= '(' ident_term (',' ident_term)... ')'

BNF通常从顶部开始向下工作,有时我会向后工作。

这是从BNF到Python pyparsing的逐步转换:

import pyparsing as pp

# we'll need a function analogous to the sum built-in for doing product
def product(values):
    ret = values[0]
    for v in values[1:]:
        ret *= v
    return ret

# symbols useful during parsing - suppress them from the output, since we
# just want the parsed and computed values
EQ, LPAR, RPAR, LBRACK, RBRACK = map(pp.Suppress, "=()[]")

# start converting the BNF to pyparsing expressions
# numeric literal from pyparsing's predefined exprs in pyparsing_common
# includes an attached parse action to convert parsed string to int or float,
# so we won't have to do that later
number = pp.pyparsing_common.number().setName("number")
ident = pp.Word(pp.alphas.upper(), pp.nums).setName("identifier")

# define placeholders for recursive elements
terms = pp.Forward().setName("terms")
factors = pp.Forward().setName("factors")

# insert grammar definitions for each - use '<<=' instead of '=' so we
# don't replace the Forward expressions, but insert the definitions into them
factor_part = number | terms
factors <<= LPAR + pp.delimitedList(factor_part) + RPAR

# when we evaluate factors, the identifiers are not used, we can suppress them
ident_factor = pp.Suppress(ident + EQ) + factors
terms <<= LBRACK + pp.delimitedList(ident_factor) + RBRACK

# add parse actions to do calculations - terms get added, factors get multiplied
terms.addParseAction(sum)
factors.addParseAction(product)

# finally define an overall expression for the sequence (P1=[...], P2=[...],
# etc.) and return as a dict
ident_term = ident + EQ + terms
parser = LPAR + pp.Dict(pp.delimitedList(pp.Group(ident_term))) + RPAR


# try parsing the given input string:
a = """(P1=[X=(0.6,3),Y=(0.4,-1)],
        P2=[X=(0.3,0),
            Y=(0.4,
               [Y1=(0.8,
                    [X=(0.2,1),Y=(0.8,2)]
                    ),
                Y2=(0.2,3)
               ]
               ),
            Z=(0.3,2)
            ],
        P3=[A=(1,1)])"""

try:
    print(parser.parseString(a).asDict())
except Exception as e:
    print(pp.ParseException.explain(e))

礼物:

{'P3': 1, 'P1': 1.4, 'P2': 1.416}