在python中将字符串表达式转换为数值

2024-09-29 03:38:52 发布

您现在位置:Python中文网/ 问答频道 /正文

最近,我得到一个面试题,题目是把字符串表达式,如“1+2-3”和“-2+4”分别转换成0和2。假设输入是个位数,数字后跟符号,没有空输入。我试过这个输出,但面试官说我很接近,但不是完美的解决方案。请帮帮我。谢谢。你知道吗

def ans(input):
    result, j = 0, 0
    for i in input:
        if i == '+' or i == '-':
            j = i
        else:
            i = int(i)
            result = result j i
    return result       
ans("1+2-3")
ans("-2+4")

我犯了一些愚蠢的错误,但我正在学习。提前谢谢。你知道吗


Tags: 字符串forinput表达式def符号数字result
3条回答

有两件事需要解决:

  1. 您需要正确地处理初始值;当初始值为非负时,这将失败。在循环之前,设置j = '+',这样就添加了一个无符号前缀的值(同样,对于样式点,j是一个糟糕的名称,可以使用op或其他什么吗?)。

  2. 不能将变量用作运算符。

替换:

result = result j i

使用:

if j == '+':
    result += i
else:
    result -= i

注:如果允许使用模块,则可以使用泛化方法以“良好”的方式处理运算符(尽管需要更多的工作来遵守运算符优先级)。你应该定义:

import operator

ops = {'+': operator.add, '-': operator.sub, ...}

然后将初始值设为opoperator.add,并将运算符的测试更改为:

if i in ops:
    op = ops[i]
else:
    result = op(result, int(i))

它可以扩展到更多的操作符,动态选择要执行的操作,而无需级联if/elif检查。你知道吗

旁注:虽然违反了挑战的精神,^{}(至少在python3.5中是这样,这可能会改变,请参见bug #22525)实际上会安全地解析这样的字符串(eval是不安全的,因为它可以执行任意代码,但是ast.literal_eval只能解析Python文本,显然还有一些基本的编译时数学)。所以你可以做:

import ast

ans = ast.literal_eval

当然,它也处理许多其他文本,但是我们从来没有定义过失败案例行为。:-)

使用eval()是最简单的解决方案。就像

eval("1+2-3")

下面的代码给出了另一个不使用内置eval的解决方案

import operator


class Parse(object):
    def __init__(self, input):
        self.input = input
        self.pos = 0
        self.end = len(input)

    def eval(self):
        result = self.match_digits()

        while self.pos < self.end:
            op = self.match_operator()
            operand = self.match_digits()
            result = op(result, operand)
        return result

    def match_operator(self):
        look_ahead = self.input[self.pos]
        self.advance()
        return operator.add if look_ahead == '+' else operator.sub

    def match_digits(self):
        look_ahead = self.input[self.pos]

        positive = 1
        if look_ahead == '-':
            positive = -1
            self.advance()

        digits, s = 0, self.pos
        while s < self.end and self.input[s].isdigit():
            digits = digits * 10 + int(self.input[s])
            s += 1
        self.advance(s-self.pos)
        return digits * positive

    def advance(self, offset=1):
        self.pos += offset

用于测试

p = Parse(input='2+1+0-3')
print p.eval()

p = Parse(input='-2+-13+3')
print p.eval()

我认为最灵活的解决方案(不使用eval并且能够处理任何操作)是将字符串解析成一个二进制(红黑)树,其中叶是数字和分支运算符(+、-、/、*等)。你知道吗

例如,"1+(5*12)/17"将被解析为以下结构:

       "+"
       / \
      1   "/"
         /   \
       "()"   17
       /
      "*"
      / \
     5   12

一旦您将一个字符串解析成这个结构,就可以通过从右到左遍历深度优先的分支来轻松计算。你知道吗

如果需要处理变量,则必须在解析字符串或遍历树时获取locals()并相应地替换。你知道吗

编辑:

我创建了一个工作示例来说明这一点,您可以在github上找到源代码:https://github.com/MJWunderlich/py-math-expression-evaluator

相关问题 更多 >