2013-05-03 74 views
3

我解析XML文件中,我得到基本的表達方式(如id*10+2)。我想要做的是評估表達式,以真正獲得價值。要做到這一點,我使用eval()這個方法效果很好。追加加「0x」的十六進制數前的字符串

的唯一的事情就是數字其實都是十六進制數。如果每個十六進制數字的前綴都是'0x',那麼eval()方法可以正常工作,但是我找不到這樣做的方法,我在這裏也找不到類似的問題。如何以一種乾淨的方式來完成?

+1

你打算怎麼解析'CAFE + BABE'? – georg 2013-05-03 08:58:07

+0

那麼,CAFE和BABE將是十六進制數字。我唯一需要注意的變量名是'Id'。 所以理想情況下,它需要'CAFE + BABE'並將其轉換爲'0xCAFE + 0xBABE' – 2013-05-03 09:02:26

+0

「open('/ tmp/a-file-on-your-system','w')等表達式怎麼樣?寫(\ 「小心!\」)「'?你有沒有試過'評估'? – Joe 2013-05-03 09:53:30

回答

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' 

它使用一個負向後斷言,以確保信i是不是正試圖轉換部分之前(防止'id'從變成'i0xd'更換iI如果變量是Id

+0

剛打好自己輸入;) – 2013-05-03 08:57:15

+0

我試過這個解決方案,但它只適用於低於'A'的數字。只要有一個十六進制字符(即從'a'到'f'),它就不會被替換(\ d +不允許字母作爲數字) – 2013-05-03 08:58:57

+0

@skndo感謝您指出了這一點。我已更新我的解決方案 – Volatility 2013-05-03 09:02:32

0

如果可以解析expresion成單個的數字,那麼我會建議使用int function

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

這確實是一個很好的解決方案,但是整個問題是正確地拆分表達式(這是因爲十六進制數字中的字母而變得很難)。不管怎麼說,還是要謝謝你! – 2013-05-03 09:52:39

0

請注意eval!千萬不要在不可信的輸入中使用它。

如果它只是簡單的算術,我會使用一個自定義的解析器(野外有大量的例子)...使用解析器生成器(flex/bison,antlr等)是一種技巧有用且容易被遺忘,所以它可能是一個很好的機會來刷新或學習它。

+1

感謝您的建議,我確實讀了一些關於您可以用'eval()'做什麼的。很可怕:D 但我用它來做快速原型(後來我會爲xml文件編寫一個C++讀取器/解析器)。另外它運行在一個封閉的網絡中,沒有連接到互聯網! 但我同意你的觀點,把它保留在最終代碼中並不是一個好主意。 – 2013-05-03 09:57:44

+0

是的,對於原型設計是好的:)...但是要警告,它很方便,你冒險永遠離開它! XD(它發生在我身上:p) – fortran 2013-05-03 10:04:42

+1

哈哈我知道它太冒險了,程序員很懶:D 但是人們會在我之後閱讀代碼,他們不會讓它這樣去(這是最好的) – 2013-05-03 10:10:24

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')(它不會用'0xBABE'代替'BABE')。

OTOH,正則表達式的解決方案是簡單,可能包括你需要處理反正所有情況。

+0

不錯的解決方案,我喜歡它!由於我只是原型設計和基本表達方式的工作,所以我保持簡單,但這種解決方案似乎避免了一些問題 – 2013-05-03 10:07:02

相關問題