从字符串列表计算 - Python

时间:2013-07-21 23:05:33

标签: python string int

我有一个python公式,可以在数字之间随机放置操作数。例如,列表可能如下所示:

['9-8+7', '7-8-6']

我想要做的是获取每个字符串的值,以便循环遍历字符串,数组将看到9-8 + 7并且将追加8和7-8-6将追加-7。我无法将带有操作数的字符串转换为int,所以这有可能吗?或者我应该更改算法,以便不是使用每个随机输出创建一个字符串,而是立即计算它的值?

提前谢谢。

3 个答案:

答案 0 :(得分:4)

您可以对列表项执行eval,但这是一个潜在的安全漏洞,只有在您完全信任来源时才能使用。

>>> map(eval, ['9-8+7', '7-8-6'])
[8, -7]

如果您控制产生字符串的代码,直接计算这些值听起来就像是一种更好的方法(更安全,可能更快)。

答案 1 :(得分:2)

正如弗雷德里克指出的那样,你可以在Python中做eval。我想我会添加一种更通用的方法,可以在任何语言中使用,并且可以为那些没有看到它们的人提供简单的解析器。

您正在描述一种语言,其正式定义如下所示:

expr := sum
sum := prod [("+" | "-") prod]...
prod := digit [("*" | "/") digit]...
digit := '0'..'9'

这个语法(我不打算制作正确的EBNF)接受这些字符串:“3”,“4 * 5/2”和“8 * 3 + 9”,依此类推。

这为我们提供了如何解析它的线索,评估不再像我们去的那样累积结果。以下是使用Python 2代码。请注意代码遵循语法的程度。

class ParseFail(Exception):
    pass

def eval_expr(str):
    value, pos = eval_sum(str, 0)
    return value

def eval_sum(str, pos):
    value, pos = eval_product(str, pos)
    accum = value
    while pos != len(str):
        op = str[pos]
        if not str[pos] in ['+', '-']:
            raise ParseFail("Unexpected symbol at position "
                            "{pos} of {str}".format(str=str, pos=pos))
        value, pos = eval_product(str, pos + 1)
        if op == '+':
            accum += value
        else:
            accum -= value
    return accum, pos

def eval_product(str, pos):
    value, pos = eval_digit(str, pos)
    accum = value
    while pos != len(str):
        op = str[pos]
        if not str[pos] in ['*', '/']:
            return accum, pos
        value, pos = eval_digit(str, pos + 1)
        if op == '*':
            accum *= value
        else:
            accum /= value
    return accum, pos

def eval_digit(str, pos):
    if not str[pos].isdigit():
        raise ParseFail("Unexpected symbol at position "
                        "{pos} of {str}".format(str=str, pos=pos))
    return int(str[pos]), pos + 1

try:
    print "3 ->", eval_expr("3")
    print "3*4 ->", eval_expr("3*4")
    print "2+3*4-5 ->", eval_expr("2+3*4-5")

    # Should raise ParseFail
    print "2+3*4^2-5 ->", eval_expr("2+3*4^2-5")
except ParseFail as err:
    print
    print err.args[0]

这是一个示例运行:

$ python simple_expr.py
3 -> 3
3*4 -> 12
2+3*4-5 -> 9
2+3*4^2-5 ->
Unexpected symbol at position 5 of 2+3*4^2-5

将此扩展为具有更多运算符的完整字符串计算器将非常容易,例如指数运算符'^'和多位整数。括号,浮点数和函数可能有点工作,但也不是那么难。在我看来,每个程序员都应该在他们的生活中尝试过一次。

答案 2 :(得分:1)

这当然取决于你的表达方式的表现和限制。

由于减法是带负数的加法,因此可以将减法写为带负数的加法。吐在+上找到条款。然后将和的项解析为整数,并求它们。对每个表达都这样做。

[sum(map(int,l.replace('-', '+-').split('+'))) for l in ['9-8+7','7-8-6']]