使用Python,我如何以前缀表示法的形式评估表达式?

时间:2012-11-14 20:56:24

标签: python parsing python-3.x

我目前正在处理名为singpath的网站上的python问题集。问题是:

前缀评估 创建一个函数,以前缀表示法的形式计算算术表达式,不带空格或语法错误。表达式以字符串形式给出,表达式中的所有数字都是整数0~9,运算符是+(加法), - (减法),*(乘法),/(除法),%(模数),其中操作与Python中的操作相同。 前缀表示法,也称为波兰表示法,是逻辑,算术和代数的一种表示形式。它将操作符放在操作数的左侧。如果运算符的arity是固定的,那么结果是缺少括号或其他括号的语法仍然可以解析而没有歧义。


这看起来很简单,但字符串在输入中没有空格,以拼接出数据。如何在不导入模块的情况下将数据与字符串分开?此外,我如何使用数据结果来解决给定的等式?另请注意,Singpath解决方案必须是 ONE 函数,不能使用标准python库中找不到的方法。这还包括在解决方案中声明的函数:S

示例:

>>> eval_prefix("+34")
7
>>> eval_prefix("*−567")
-7
>>> eval_prefix("-*33+2+11")
5
>>> eval_prefix("-+5*+1243")
14
>>> eval_prefix("*+35-72")
40
>>> eval_prefix("%3/52")
1

看到我的观点没有空格D:

6 个答案:

答案 0 :(得分:3)

我认为这里的关键点是“表达式中的所有数字都是整数0~9”。所有数字都是单个数字。您不需要空格来查找一个数字结束的位置以及下一个数字的开始位置。您可以通过字符串索引直接访问这些数字,正如lckknght所说。

要将字符串中的字符转换为整数进行计算,请使用ord(ch) - 48(因为“0”具有ASCII码48)。因此,要获得存储在输入位置5的数字,请使用ord(输入[5]) - 48。

要评估嵌套表达式,可以递归调用函数。这里的关键假设是操作员总是有两个操作符。

答案 1 :(得分:2)

你的“一个功能”限制没有你想象的那么糟糕。 Python允许在函数内定义函数。最后,函数定义只不过是将函数赋值给(通常是新的)变量。在这种情况下,我认为你会想要使用递归。虽然这也可以在没有额外功能的情况下完成,但您可能会发现为它定义额外的递归函数更容易。这对您的限制没有问题:

def eval_prefix (data):
    def handle_operator (operator, rest):
        # You fill this in.
    # and this, too.

这应该是一个提示(如果你想使用递归方法)。

答案 2 :(得分:2)

那么,单线适合吗? python3中的Reduce隐藏在functools中 有些lispy:)

eval_prefix = lambda inp:\
            reduce(lambda stack, symbol:\
            (
              (stack+[symbol]) if symbol.isdigit() \
             else \
              (
                stack[:-2]+\
                [str(
                      eval(
                           stack[-1]+symbol+stack[-2]
                          )
                    )
                ]
              )
            ), inp[::-1], [])[0]

答案 3 :(得分:2)

好吧,不像alex jordan的lamba / reduce解决方案那样时髦,但它并没有扼杀垃圾输入。这是一种递归下降解析器遇到冒泡排序的憎恶(我认为当它找到一个可解决的部分而不仅仅是跳回到开始时可能会更有效。)

import operator
def eval_prefix(expr):
    d = {'+': operator.add,
         '-': operator.sub,
         '*': operator.mul,
         '/': operator.div, # for 3.x change this to operator.truediv
         '%': operator.mod}
    for n in range(10):
        d[str(n)] = n
    e = list(d.get(e, None) for e in expr)
    i = 0
    while i + 3 <= len(e):
        o, l, r = e[i:i+3]
        if type(o) == type(operator.add) and type(l) == type(r) == type(0):
            e[i:i+3] = [o(l, r)]
            i = 0
        else:
            i += 1
    if len(e) != 1:
        print 'Error in expression:', expr
        return 0
    else:
        return e[0]

def test(s, v):
    r = eval_prefix(s)
    print s, '==', v, r, r == v

test("+34", 7)
test("*-567", -7)
test("-*33+2+11", 5)
test("-+5*+1243", 14)
test("*+35-72", 40)
test("%3/52", 1)
test("****", 0)
test("-5bob", 10)

答案 4 :(得分:0)

您最有可能寻找的提示是“字符串可迭代”:

def eval_prefix(data):
    # setup state machine
    for symbol_ in data:
        # update state machine

答案 5 :(得分:0)

分离字符串的元素很容易。所有元素都是单个字符长,因此您可以直接迭代(或索引)字符串以获取每个元素。或者,如果您希望能够操作值,则可以将字符串传递给list构造函数。

以下是一些如何运作的例子:

string = "*-567"

# iterating over each character, one at a time:
for character in string:
    print(character) # prints one character from the string per line

# accessing a specific character by index:
third_char = string[2] # note indexing is zero-based, so 3rd char is at index 2

# transform string to list
list_of_characters = list(string) # will be ["*", "-", "5", "6", "7"]

至于如何解决方程,我认为有两种方法。

一种方法是使函数递归,这样每次调用都会计算单个操作或文字值。这有点棘手,因为你只应该使用一个函数(如果你有一个递归的辅助函数,使用与主非递归函数不同的API调用它会更容易)。

另一种方法是建立一堆值和操作,等待在输入字符串上进行一次迭代时等待评估。考虑到单功能限制,这可能更容易。