【问题标题】:Using Python, How can I evaluate an expression in the form of prefix notation compacted?使用 Python,如何以压缩前缀符号的形式评估表达式?
【发布时间】:2012-11-14 20:56:23
【问题描述】:

我目前正在一个名为 singpath 的网站上研究 python 问题集。问题是:

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


这看起来很简单,但是字符串被压缩了,输入中没有空格来拼接数据。如何在不导入模块的情况下将数据与字符串分开?此外,我如何使用数据结果来求解给定的方程?另外请记住,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:

【问题讨论】:

    标签: python parsing python-3.x


    【解决方案1】:

    好的,不像 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)
    

    【讨论】:

    • 谢谢约翰!你的代码对我来说比 lambda 表达式更容易理解(我还是个初学者,不知道)。回想起来,我应该在 python 库中寻找一个操作员模块!因为我很傻(并且倾向于忽略一些事情),所以我的主要问题是填写我的清单。我没有使用 range() 方法,而是尝试直接将字符串更改为列表..而不验证列表中的类型。如果(何时)我获得足够的声誉,我肯定会支持您的解决方案!感谢您的帮助!
    【解决方案2】:

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

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

    要计算嵌套表达式,您可以递归调用函数。这里的关键假设是一个操作符总是恰好有两个操作符。

    【讨论】:

    • 当我输入答案时,我考虑过使用 ascii 值,但决定不尝试,因为我想以全新的眼光看待问题:P 谢谢你的建议!
    【解决方案3】:

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

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

    这应该是足够的提示(如果您想使用递归方法)。

    【讨论】:

    • 和 Sean 一样 :P 我不擅长递归,所以我应该查一下它的教程/分解 :P 谢谢你的提示!如果我没有在上面得到详细的答案,那么我会在互联网上搜索递归,这将引导我朝着正确的方向前进。干杯!
    • 我从来不知道你可以在一个我认为是大忌的函数中创建一个函数。 :P 感谢您的提示,以后应该好好利用它!编辑:当我输入此内容时,我之前的评论不存在...我更喜欢这个...再次感谢!
    【解决方案4】:

    嗯,单线适合吗? python3中的reduce隐藏在functools中 有点口齿不清:)

    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]
    

    【讨论】:

    • 感谢您提供复杂的代码...唯一的问题...我是编程初学者....我还不是 Pythonista :P 所以...随意如果您想真正提供帮助,请稍微扩展一下 XD
    【解决方案5】:

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

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

    【讨论】:

    • 谢谢肖恩,但我有很多失望......问题是从字符串到列表的转换和正确的递归......我对这些东西很陌生:P 谢谢XD
    【解决方案6】:

    分离字符串的元素很容易。所有元素都是单个字符长,因此您可以直接迭代(或索引)字符串以获取每个元素。或者,如果您希望能够操作这些值,您可以将字符串传递给 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 调用递归辅助函数,那会容易得多)。

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

    【讨论】:

    • 啊...愚蠢的计算机偷走了我的评论 :P 所以细分:非常感谢您对递归的定义(和建议),一个易于阅读的字符串 -> 列表转换,最重要的是您的时间。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    相关资源
    最近更新 更多