在字符串中的十六进制数字前面添加“0x”

时间:2013-05-03 08:53:53

标签: python parsing

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

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

4 个答案:

答案 0 :(得分: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输入无效,则无效。还有many risks使用eval

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

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

这使用负面的lookbehind断言来确保字母i不在它试图转换的部分之前(阻止'id'变成'i0xd'。替换{{1}如果变量为i,则I

答案 1 :(得分:0)

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

>>> int("CAFE", 16)
51966

答案 2 :(得分:0)

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

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

答案 3 :(得分: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,正则表达式解决方案更简单,可能涵盖您需要处理的所有案例。