Python 正則是否存在前向貪婪匹配呢?
阿新 • • 發佈:2019-01-07
場景描述
由於專案的某一些應用場景出現瞭如下的需求:
A: str = “ABCABABCABABC”
B: 將其中ABC都摳出來
猛一看,這還不easy呢? 直接 ABC匹配不就出來了嗎?
str = "ABCABABCABABC"
res = re.findall(r'ABC', str, re.M)
這結果不就出來了嗎?
可是難就難在這邊,這邊的ABC並非真實的字母,而是一個泛指 。具體的str參見如下描述:
str1 = "a:bc123cdf\ddd1 d32sfdfds2332fsd1 \n data:dsafdsfssdfsd\nalert ===> virus\n" \ "a:bc123cdfd\ddd2 32sfdfds2332fsd1 \n data:dsafdsfssdfsd end222end!!!!\n" \ "a:bc123cdfd\ddd3 32sfdfds2332fsd1 \n data:dsafdsfssdfsd\nalert===> no virus\n" \ "a:bc123cdfd\ddd3 32sfdfds2332fsd1 \n data:dsafdsfssdfsd\nalert===> no virus\n" \ "a:bc123cdfd\ddd2 32sfdfds2332fsd1 \n data:dsafdsfssdfsd end33333end!!!\n"
要求:
1、我們忽略'\n',可以看到我們這邊暫時分為了五行,我們要做到的事: 匹配第一、三、四行資料
2、扣除 一三四行中\後面的ddd1、ddd3以及與之對應的 alert結果 no virus
實戰分析
既然題目已經給出了, 那麼我們就來做吧。 對於正則,我想大部分人已經非常熟悉了。
首先,我們必須忽略'\n', 那麼我們必須使用re庫中的S,表示忽略\n換行符。
sp = re.findall("a[:].*?data[:].*?alert.*?\n", str1, re.S) print sp for i in range(len(sp)): print sp[i]
這是我一開始給出的正則表示式,可惜得到的結果不盡人意:
a:bc123cdf\ddd1 d32sfdfds2332fsd1 data:dsafdsfssdfsd alert ===> virus a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end222end!!!! a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus
我們可以看到,結果分割出來 起始 和結束都沒有問題,但是中間 類似於“ABABC”卻被匹配上了。這不是我們想要的。
正則的前向貪婪匹配
我們都知道,正則有自己的貪婪模式,可以向後匹配最近的欄位。那麼我們能不能根據alert欄位匹配前面最近的AB呢?
str2 = "00000aaaaa111111aaa00000bbbbb11111"
res2 = re.findall(r'(?<=0)(?!0)\w+?(?=1)', str2)
print res2
#結果
['aaaaa', 'bbbbb']
可惜呢,找了全網 基本都沒有我們想要的結果。於是乎 這條路基本就算走死了。
《如果以後,發現了 再回來!!!!! 》
最終解決
似乎,我們想要的都不是我們期望的,那行吧,既然前向走不通,那就最簡單的方式吧。
將所有
\n data ==》 data
\n alert ==》 alert
那麼我們的串將變為:
str1 = "a:bc123cdf\ddd1 d32sfdfds2332fsd1 data:dsafdsfssdfsd alert ===> virus\n" \
"a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end222end!!!!\n" \
"a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus\n" \
"a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus\n" \
"a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end33333end!!!\n"
結果卻依然沒有改變ABABC這樣的問題,
a:bc123cdf\ddd1 d32sfdfds2332fsd1 data:dsafdsfssdfsd alert ===> virus
a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end222end!!!!
a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus
a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus
但是我們接著對上述結果 進行再匹配(原先的中間間隔換行不太好搞) 注意這邊使用的re.M 不寫或者re.S都會出錯!!!
res = re.findall(r'a:.*?\\(.*?) .*?===>(.*?)\n', str1, re.M)
print res
#結果
[('ddd1', ' virus'), ('ddd3', ' no virus'), ('ddd3', ' no virus')]
總結下吧
對於這種多換行的正則匹配,沒有好的辦法 可以替換 換行,最後在替換回來的辦法 進行匹配檢索!!!!
最後附上完整程式碼 練習使用!
# encoding:utf-8
import re
str1 = "a:bc123cdf\ddd1 d32sfdfds2332fsd1 data:dsafdsfssdfsd alert ===> virus\n" \
"a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end222end!!!!\n" \
"a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus\n" \
"a:bc123cdfd\ddd3 32sfdfds2332fsd1 data:dsafdsfssdfsd alert===> no virus\n" \
"a:bc123cdfd\ddd2 32sfdfds2332fsd1 data:dsafdsfssdfsd end33333end!!!\n"
sp = re.findall("a[:].*?data[:].*?alert.*?\n", str1, re.S)
print sp
for i in range(len(sp)):
print sp[i]
str2 = "00000aaaaa111111aaa00000bbbbb11111"
res2 = re.findall(r'(?<=0)(?!0)\w+?(?=1)', str2)
print "11111"
print res2
res = re.findall(r'a:.*?\\(.*?) .*?===>(.*?)\n', str1, re.M)
print res
str = "ABCABABCABABC"
res = re.findall(r'ABC', str, re.M)
print res