2012-05-24 79 views
4

我試圖提取從如下字符串現在在正則表達式條件匹配

>>> st = ''' 
... <!-- info mp3 here --> 
...        192 kbps<br />2:41<br />3.71 mb </div> 
... <!-- info mp3 here --> 
...        3.49 mb </div> 
... <!-- info mp3 here --> 
...        128 kbps<br />3:31<br />3.3 mb </div> 
... ''' 
>>> 

,當我使用了一些資料下面的正則表達式,我的輸出是

>>> p = re.findall(r'<!-- info mp3 here -->\s+(.*?)<br />(.*?)<br />(.*?)\s+</div>',st) 
>>> p 
[('192 kbps', '2:41', '3.71 mb'), ('128 kbps', '3:31', '3.3 mb')] 

,但我需要的輸出是

[('192 kbps', '2:41', '3.71 mb'),(None,None,'3.49mb'), ('128 kbps', '3:31', '3.3 mb')] 

所以,我的問題是如何改變我的以上regex以匹配所有條件。我相信我目前的正則表達式嚴格依賴於<br />標籤,所以我如何使它成爲條件。

我知道我不應該使用正則表達式來解析html,但目前這是對我來說最合適的方式。

回答

6

下面的工作,但我不知道是否沒有更優雅的解決方案。您當然可以將列表理解合併爲一行,但我認爲這會使整個代碼更清晰。至少這樣你就可以跟着你做了什麼,再過三個月......

st = ''' 
<!-- info mp3 here --> 
          192 kbps<br />2:41<br />3.71 mb </div> 
<!-- info mp3 here --> 
          3.49 mb </div> 
<!-- info mp3 here --> 
          128 kbps<br />3:31<br />3.3 mb </div> 
''' 

p = re.findall(r'<!-- info mp3 here -->\s+(.*?)\s+</div>',st) 
p2 = [row.split('<br />') for row in p] 
p3 = [[None]*(3 - len(row)) + row for row in p2] 

>>> p3 
[['192 kbps', '2:41', '3.71 mb'], [None, None, '3.49 mb'], ['128 kbps', '3:31', '3.3 mb']] 

,並根據您的字符串的變化,你可能需要編寫一個更通用的清潔功能能帶,案件,無論如何,並將其映射到您拉出的每件物品。

2

這是一個正則表達式的解決方案,通過更具體一些。我不確定這是否優於Karmel的回答,但我想我會按照問題回答問題。而不是返回None,前兩個可選組返回空字符串'',我認爲這可能足夠接近。

請注意嵌套的組結構。前兩個外部組是可選的,但需要<br />標記才能匹配。這樣一來,如果有少於兩個<br />標籤,最後一個項目不匹配,直到結束:

rx = r'''<!--\ info\ mp3\ here\ -->\s+ # verbose mode; escape literal spaces 
     (?:        # outer non-capturing group 
      ([^<>]*)      # inner capturing group without <> 
      (?:<br\ />)     # inner non-capturing group matching br 
     )?        # whole outer group is optional 
     (?:        
      ([^<>]*)      # all same as above 
      (?:<br\ />)     
     )? 
     (?:        # outer non-capturing group 
      (.*?)      # non-greedy wildcard match 
      (?:\s+</div>)    # inner non-capturing group matching div 
     )'''       # final group is not optional 

測試:

>>> re.findall(rx, st, re.VERBOSE) 
[('192 kbps', '2:41', '3.71 mb'), 
('', '', '3.49 mb'), 
('128 kbps', '3:31', '3.3 mb')] 

注意re.VERBOSE標誌,除非你刪除這是必要的上面的所有空白和註釋。