Python 正則是否存在前向貪婪匹配呢?

tiny丶發表於2018-10-22

場景描述

由於專案的某一些應用場景出現瞭如下的需求:

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

 

相關文章