2014-09-03 10 views
0

我有以下的正則表達式應該拉出3組正則表達式分組不是預期

^(ser-num.*|\[ser-num.*])(?:)?(\w+)?(?:)?(http://.*\.com/(?:s(?:erial)?|p(?:roduct)?)/\d+(?:/)?(?:\d+|(?:\w|-)+)?) 

這兩個字符串:

strings = [ 
    "ser-num recommend http://example.com/s/123456 ", 
    "ser-num http://example.com/s/123456 ", 
] 

當我運行這些對正則表達式我收到以下組:

('ser-num recommend ', None, 'http://example.com/s/123456') 
('ser-num ', None, 'http://example.com/s/123456') 

爲什麼我的第一個結果結合「推薦」成組\1,而不是\2

這是我整個示例腳本:

import re 

p = re.compile("""^(ser-num.*|\[ser-num.*])(?:)?(\w+)?(?:)?(http://.*\.com/(?:s(?:erial)?|p(?:roduct)?)/\d+(?:/)?(?:\d+|(?:\w|-)+)?)""") 

strings = [ 
    "ser-num recommend http://example.com/s/123456 ", 
    "ser-num http://example.com/s/123456 ", 
] 

for s in strings: 
    m = p.match(s) 
    try: 
     print m.groups() 
    except AttributeError: 
     print "Not a match for %s" % (s) 

我正則表達式的explanation說,可選的組\2確實存在。

更新基於評論:

如果我利用這個正則表達式

^(ser-num.*|\[ser-num.*])\s?(\w*)\s?(http://.*\.com/(?:s(?:erial)?|p(?:roduct)?)/\d+(?:/)?(?:\d+|(?:\w|-)+)?) 

我收到這些結果(請注意組\2空字符串而非None

('ser-num recommend ', '', 'http://example.com/s/123456') 
('ser-num ', '', 'http://example.com/s/123456') 
+0

爲什麼使用'(?:)?'作爲空格而不是使用'?'? – RevanProdigalKnight 2014-09-03 18:45:52

+0

或者甚至可能是'\ s *'爲空格,而'(\ w *)'爲可選詞? – abiessu 2014-09-03 18:46:39

+1

'。*'是罪魁禍首,使用'\ S *'進行貪婪的非空格字符匹配。 – abiessu 2014-09-03 18:57:14

回答

2

我建議以下正則表達式:

^(\[?ser-num\S*]?)\s*(\w*)\s*(http://.*\.com/(?:s(?:erial)?|p(?:roduct)?)/\d+(?:/)?(?:\d+|(?:\w|-)+)?) 

這個(特別是\S*代替.*)強制(\w*)處於其自己的捕獲組中,而不是被任何字符組的第一個貪婪的ser-num.*吞噬。請注意,由於相同的原因,第一組中還有額外的空格,即它們被貪婪地捕獲而不是被視爲可選匹配而被丟棄。

1

單詞recommend是第一組的一部分,因爲它匹配部分正則表達式ser-num.*。星號運算符返回儘可能長的匹配。如果您想要儘可能短的匹配,請使用*?

試試這個:

p = re.compile("""^(ser-num.*?|\[ser-num.*?])(?:)?(\w+)?(?:)?(http://.*\.com/(?:s(?:erial)?|p(?:roduct)?)/\d+(?:/)?(?:\d+|(?:\w|-)+)?)""") 

注意使用非貪婪的明星:ser-num.*?

參考:

+0

而顯而易見的「應用非貪婪匹配」提供了最簡單的變化。 +1 – abiessu 2014-09-03 18:59:07