3

我正在解析一个 xml 文件,在其中我得到基本表达式(如id*10+2)。我要做的是评估表达式以实际获取值。为此,我使用eval()效果很好的方法。

唯一的问题是这些数字实际上是十六进制数字。如果每个十六进制数字都以“0x”为前缀,则该eval()方法可以很好地工作,但是我找不到方法,在这里也找不到类似的问题。如何以干净的方式完成?

4

4 回答 4

4

使用re模块。

>>> import re
>>> re.sub(r'([\dA-F]+)', r'0x\1', 'id*A+2')
'id*0xA+0x2'
>>> eval(re.sub(r'([\dA-F]+)', r'0x\1', 'CAFE+BABE'))
99772

但是请注意,如果输入无效eval,它将无法正常工作。使用也有很多风险eval

如果您的十六进制数字有小写字母,那么您可以使用:

>>> re.sub(r'(?<!i)([\da-fA-F]+)', r'0x\1', 'id*a+b')
'id*0xa+0xb'

这使用否定的lookbehind断言来确保字母i不在它尝试转换的部分之前(防止'id'变成.如果变量是. 则'i0xd'替换i为.IId

于 2013-05-03T08:56:52.200 回答
0

如果您可以将表达式解析为单个数字,那么我建议使用int 函数

>>> int("CAFE", 16)
51966
于 2013-05-03T09:51:22.210 回答
0

小心eval!永远不要在不受信任的输入中使用它。

如果它只是简单的算术,我会使用自定义解析器(野外有大量示例)......并且使用解析器生成器(flex / bison,antlr等)是一种有用且容易忘记的技能,所以这可能是一个刷新或学习它的好机会。

于 2013-05-03T09:53:47.680 回答
0

一种选择是使用该parser模块:

import parser, token, re

def hexify(ast):
    if not isinstance(ast, list):
        return ast
    if ast[0] in (token.NAME, token.NUMBER) and re.match('[0-9a-fA-F]+$', ast[1]):
        return [token.NUMBER, '0x' + ast[1]]
    return map(hexify, ast)

def hexified_eval(expr, *args):
    ast = parser.sequence2st(hexify(parser.expr(expr).tolist()))
    return eval(ast.compile(), *args)

>>> hexified_eval('id*10 + BABE', {'id':0xcafe})
567466

这比正则表达式解决方案要干净一些,因为它只尝试替换已确定为名称或数字(并且看起来像十六进制数字)的标记。它还可以正确处理更通用的 python 表达式,例如id*10 + len('BABE')(它不会替换'BABE''0xBABE')。

OTOH,正则表达式解决方案更简单,并且可能涵盖您需要处理的所有情况。

于 2013-05-03T10:03:29.190 回答