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

时间:2016-01-14 01:57:42

标签: python string

最近,我收到了一个面试问题,说要转换字符串表达式,如" 1 + 2-3"和" -2 + 4"分别为0和2。假设输入是单位数字后跟符号而没有NULL输入。我试过这个输出,但面试官说我很接近但不是完美的解决方案。请帮帮我。感谢。

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")

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

4 个答案:

答案 0 :(得分:5)

两件事需要修复工作:

  1. 您需要正确处理初始值;当初始值为非负值时,此操作失败。在循环之前,设置j = '+'以便添加一个非符号前缀值(同样,对于样式点,j是一个可怕的名称,您可以使用op或其他什么吗?)。< / p>

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

  3. 替换:

    result = result j i
    

    使用:

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

    注意:如果允许模块,可以使用泛化来处理运算符&#34; nice&#34;方式(虽然需要更多的工作来遵守运营商的优先权)。你定义了:

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

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

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

    可扩展到更多运算符,动态选择要执行的操作,而无需级联if / elif检查。

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

    ast.literal_eval

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

答案 1 :(得分:1)

使用 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()

答案 2 :(得分:1)

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

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

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

一旦你将一个字符串解析为这个结构,通过遍历分支深度优先,从右到左,它很容易计算。

如果您需要处理变量,那么您必须得到locals()并相应地替换,无论是在解析字符串时,还是在遍历树时。

编辑:

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

答案 3 :(得分:-1)

怎么样:

def f(s):
    s = s.strip()
    for i, c in enumerate(s):
        if c == '+':
            return f(s[:i]) + f(s[i+1:])
        if c == '-':
            return f(s[:i]) - f(s[i+1:])
    for i, c in enumerate(s):
        if c == '*':
            return f(s[:i]) * f(s[i+1:])
        if c == '/':
            return f(s[:i]) / f(s[i+1:])
    return 0 if s == '' else int(s)

?不适用于括号