2012-05-24 77 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标志,除非你删除这是必要的上面的所有空白和注释。