2012-02-21 87 views
0

我有一些我想匹配的短語。我用一個正則表達式如下:使用正則表達式和Python進行短語匹配

(^|)(piston|piston ring)(|$) 

上的「活塞」使用以上,regex.match("piston ring")匹配。如果我改變正則表達式,使得更長的短語「活塞環」首先出現,然後按預期工作。

我對這種行爲感到驚訝,因爲我假設正則表達式的貪婪本質會嘗試匹配最長的字符串「免費」。

我錯過了什麼?有人可以解釋這一點嗎?謝謝!

+1

正則表達式貪婪只有在使用'*'和'+'運算符時纔會生效。 '|'使用從左到右的第一個匹配項。 – resmon6 2012-02-21 20:13:38

回答

5

當使用正則表達式交替(|),每個選項試圖按照從左至右,直到比賽可以找到。因此,在您的示例中,由於可以使用piston進行匹配,因此將永遠不會嘗試piston ring

一種更好的方式來寫這個正則表達式將是這樣的:

(^|)(piston(ring)?)(|$) 

這將嘗試匹配'piston',然後立即嘗試匹配' ring',與?使其可選。或者,只要確保您的更長期的選擇發生在交替的開始。

您可能還需要考慮使用word boundary\b,而不是(^|)(|$)

+0

+1爲您的替代解決方案 – stema 2012-02-21 20:20:21

+0

我按照相反的順序排列我的列表的長度以獲得良好的結果。我也接受了您的建議,並使用\ b來清晰。謝謝您的幫助! – ccgillett 2012-02-21 20:36:53

2

這就是交替的行爲。它試圖匹配第一個選擇,即「活塞」,如果它成功完成。

這意味着它不會嘗試所有的選擇,它會完成與匹配的第一個。

你可以在這裏找到regular-expressions.info

更多的細節你字界限\b什麼也可能是有趣的。我知道你在尋找的是

\bpiston(?: ring)?\b 
4

http://www.regular-expressions.info/alternation.html(第一谷歌的結果):

正則表達式引擎是躍躍欲試。一旦發現有效匹配,它將停止搜索。其結果是,在某些情況下,替代品的順序事項

一個例外:

的POSIX標準授權最長匹配退還,如果不考慮正則表達式引擎是使用NFA實現或DFA算法。

可能的解決方案:

  • piston(ring)?
  • (piston ring|piston)(放之前最長)
+1

這也很好理解爲什麼重複表達式是貪婪的。 http://www.regular-expressions.info/repeat.html – resmon6 2012-02-21 20:19:05

0
Edit2: It wasn't clear if your test data 
contained pipes or not. I saw the pipes in 
the regex and assumed you are searching 
for pipe delim. Oh well.. not sure if below 
helps. 

使用正則表達式匹配文本的菸斗分隔將需要更多的交替回暖開始和結束列。

另一種方法呢?

text='start piston|xxx|piston ring|xxx|piston cast|xxx|piston|xxx|stock piston|piston end' 
j=re.split(r'\|',text) 

k = [ x for x in j if x.find('piston') >= 0 ] 
['start piston', 'piston ring', 'piston cast', 'piston', 'stock piston', 'piston end'] 

k = [ x for x in j if x.startswith('piston') ] 
['piston ring', 'piston cast', 'piston', 'piston end'] 

k = [ x for x in j if x == 'piston' ] 
['piston'] 

j=re.split(r'\|',text) 
if 'piston ring' in j: 
    print True 
> True 

編輯:澄清 - 藉此例如:

文本2 = 'piston1 | XXX | spiston2 | XXX |活塞環| XXX | piston3'

我添加 ''搭配什麼可以炫耀的項目匹配

re.findall('piston.',text2) 
['piston1', 'piston2', 'piston ', 'piston3'] 

爲了使它更精確,你將需要使用向後看斷言。 這樣可以保證你匹配「|活塞」,但不包括管的結果,從貪婪到第一個匹配的字符

re.findall('(?<=\|)piston.',text2) 
['piston ', 'piston3'] 

限制匹配。*? <停止字符> 添加分組零件以排除管道。比賽。*?足夠聰明地檢測是否在組內並忽略paren並使用下一個字符作爲停止匹配哨兵。這似乎工作,但它忽略了最後一列。

re.findall('(?<=\|)(piston.*?)\|',text2) 
['piston ring'] 

當你添加分組現在你只需用一個轉義管指定開始

re.findall('\|(piston.*?)\|',text2) 
['piston ring'] 

要搜索的最後一列,以及添加此非分組匹配(?:\ $ ||) - 表示匹配管道(需要轉義)或(|)字符串的結尾($)。 非分組匹配(?:x1 | x2)未包含在結果中。它得到優化的額外獎勵。

re.findall('\|(piston.*?)(?:\||$)',text2) 
['piston ring', 'piston3'] 

最後,要解決的字符串的開頭,再添改變很像以前的一個最終的字符串匹配

re.findall('(?:\||^)(piston.*?)(?:\||$)',text2) 
['piston1', 'piston ring', 'piston3'] 

希望它能幫助。 :)