2015-10-08 135 views
0

我有一個巨大的日誌文件,我必須從中提取特定的模式或字節數組。 每一行看起來是這樣的:從文件中提取子字符串

<<< 10:39:01.296 [0x01|0x02|0x04|0x05] [0x00|0xDE|0xAD] (Value: Check) 

從這一行我已經提取字節寫0xDE和寫0xAD。

日誌模式是通常的形式(只XX和YY是變體):

<<< 10:39:01.296 [0x01|0x02|0x04|0x05] [0x00|0xXX|0xYY] (Value: Check) 

要嘗試,我有這個圖案爲一個字符串,下面的代碼檢查。不過,我覺得必須有比這更好的方式。你能給些建議麼?

input= """<<< 10:39:01.296 [0x01|0x02|0x04|0x05] [0x00|0xDE|0xAD] (Value: Check) """ 

#extract 0xDE and 0xAD and join them to read DEAD 


c = input.find("]") 
d = input.find('[', c) 
e = input.find("]", d) 
mystr = input[d+6:e] 
x,y = mystr.split('|0x', 1) 

print x 
print y 
numStr = ''.join(mystr.split('|0x', 1)) 


print numStr 
#val = int(numStr,16) 
#print val: 
+0

問題是不清楚的。它將永遠是0xDE和0xAD。 。你想提取什麼,或者你需要得到最後兩個字節? – csharpcoder

回答

0

如果格式總是在第二塊三個字節,第一塊從未有三個字節,而你只關心塊的兩個字節,那麼這裏有一對夫婦的做法。

一種方法是通過從右側開始搜索並使用異常提升搜索方法來簡化對搜索塊的搜索(因此,您不需要明確檢查返回值以查看find是否成功try/except和跳過行,如果它沒有預期的數據):

mystr = input[input.rindex('[')+1:input.rindex(']')] 
byteparts = mystr.split('|') 
byte1, byte2 = byteparts[1:] # Unlike the above, this keeps the 0x, but that's trivially stripped if you care 
# By using [1:] as the slice and unpacking the result, if you got a set 
# of matches that isn't three bytes long, you'll get an exception on unpack 

採用rindex意味着你可以忽略第一塊(你永遠不會得到它),如果搜索失敗,它會立即引發錯誤,而不是返回-1,並且默默無聞地行事。

另一種解決方案是使用正則表達式(我說這很不情願;太多的人作爲第一個度假勝地接觸正則表達式,這通常是一個壞主意,但對於足夠奇怪的情況,有時候比建立你的來自方法調用的邏輯)。這樣就解決了上述問題,並可以通過調整正則表達式處理更爲複雜的變體:

import re 

input = ... 

match = re.search(r'\[0x..\|0x([0-9a-f]{2})\|0x([0-9a-f]{2})\]', input, re.I) 

if match is not None: 
    byte1, byte2 = match.groups() 
+0

注意:如果問題甚至比您提供的更復雜一點,那麼正則表達式在這裏很有用。如果可以用'rindex'方法解決,我會堅持。 – ShadowRanger

0

如果你不想使用正則表達式,你的日誌模式總是看起來像你的樣品,你可以做一個醜陋的一行

print ''.join(item.replace('0x', '') for item in input.split('[')[2].split(']')[0].split('|')[1:]) 
>>> 'DEAD' 
0

隨着如規定的問題,你想要什麼,但下面將輸出不知何故,我得到的感覺是你的問題似乎沒有什麼,有一個很大的缺點什麼。

>>> res = ''.join(input[46:55].split('|0x',1)).split('0x',1)[1] 
>>> if res == 'DEAD': print res 
... 
DEAD 

或怎麼樣:

>>> input= "<<< 10:39:01.296 [0x01|0x02|0x04|0x05] [0x00|0xDE|0xAD] (Value: Check) " 
>>> if '|0xDE|0xAD]' in input: 
...  print "DEAD occurred at ", input[4:16] 
... 
DEAD occurred at 10:39:01.296 

或:

>>> if input.rfind('|0xDE|0xAD]') > 40: 
...  print "DEAD occurred at ", input[4:16] 
... 
DEAD occurred at 10:39:01.296 
+0

即使您可以使用幻數(因爲該行具有固定佈局),但出於可維護性原因,我會感到非常不舒服;代碼的邏輯幾乎沒有提及它正在尋找什麼,所以如果日誌格式發生變化,則需要引用舊日誌來解釋代碼,以便更新它。假設你甚至注意到這個問題;在許多情況下,這將會導致錯誤併產生不正確的輸出,並且不會引發任何類型的異常(即使在空字符串上操作時)。 – ShadowRanger

+0

@ShadowRanger我同意但是這就是爲什麼我還添加了一個相當大的警告。如果問題發生了變化,或者有一條評論使得它更清晰,我會很樂意刪除這個答案。 –

+0

不,我的觀點是,即使問題完全是*您認爲的問題,幻數和錯誤檢查都是危險的,因爲問題會改變,即使他們以後不需要閱讀代碼,有一些想法應該做什麼。 我同意它可能解決了這個問題,即使它存在,它也只是一個壞主意。 – ShadowRanger

0

最後兩個數字可以提取如下:

import re 

text = "<<< 10:39:01.296 [0x01|0x02|0x04|0x05] [0x00|0xDE|0xAD] (Value: Check)" 
parts = re.split(r'[|\]]', text) 

print int(parts[-3], 16) 
print int(parts[-2], 16) 

,並提供:

222 
173 

注意:最好不要使用名爲input的變量,因爲這是內置的Python函數。