更好的方式使用re.sub

时间:2014-05-07 16:41:11

标签: python html regex html-parsing

我正在从推特流中清理一系列来源。 以下是数据示例:

source = ['<a href="https://twitter.com/download/android" rel="nofollow">Twitter for Android Tablets</a>', 
          '<a href="https://twitter.com/download/android" rel="nofollow">Twitter for  Android</a>',
          '<a href="http://foursquare.com" rel="nofollow">foursquare</a>', 'web',
          '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>',
          '<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry</a>']


import re
for i in source:
    re.sub('<.*?>', '', re.sub(r'(<.*?>)(Twitter for)(\s+)', r'', i))

### This would be the expected output ###
'Android Tablets'
'Android'
'foursquare'
'web'
'iPhone'
'BlackBerry'

后者是我完成工作的代码,但看起来很糟糕。我希望有更好的方法可以做到这一点,包括re.sub()或其他可能更适合的功能。

5 个答案:

答案 0 :(得分:4)

另一种选择,使用BeautifulSoup html解析器:

>>> from bs4 import BeautifulSoup
>>> for link in source:
...     print BeautifulSoup(link, 'html.parser').text.replace('Twitter for', '').strip()
... 
Android Tablets
Android
foursquare
web
iPhone
BlackBerry

答案 1 :(得分:2)

如果您正在做很多这些,请使用专为处理(X)HTML而设计的库。 lxml效果很好,但我对BeautifulSoup包装更熟悉。

from bs4 import BeautifulSoup

source = ['<a href="https://twitter.com/download/android" rel="nofollow">Twitter for Android Tablets</a>', 
      '<a href="https://twitter.com/download/android" rel="nofollow">Twitter for  Android</a>',
      '<a href="http://foursquare.com" rel="nofollow">foursquare</a>', 'web',
      '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>',
      '<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry</a>']

soup = BeautifulSoup('\n'.join(source))
for tag in soup.findAll('a'):
    print(tag.text)

但是,对于您的用例,这可能有点过分。

答案 2 :(得分:2)

这里有改进代码的建议:

  • 使用正则表达式编译,这样每次应用正则表达式时都不会处理正则表达式,
  • 使用原始字符串来避免python,
  • 对正则表达式字符串的任何解释
  • 使用一个正则表达式,除了结束标记字符之外,它还可以在标记
  • 中进行匹配
  • 您不需要重复替换,因为它会匹配默认情况下每次出现的次数

这是一个更简单,更好的结果:

>>> import re
>>> r = re.compile(r'<[^>]+>')
>>> for it in source:
...     r.sub('', it)
... 
'Twitter for Android Tablets'
'Twitter for  Android'
'foursquare'
'web'
'Twitter for iPhone'
'Twitter for BlackBerry'

N.B。:针对您的用例的最佳解决方案是@ bakuriu的建议:

 >>> for it in source:
 ...     it[it.index('>')+1:it.rindex('<')]
'Twitter for Android Tablets'
'Twitter for  Android'
'foursquare'
'Twitter for iPhone'
'Twitter for BlackBerry'

它不会增加重要的开销,并使用基本的快速字符串操作。但是该解决方案仅 或者根本没有标签,即它不会对<a>字符串起作用。根本没有标签的解决方案:

</a>

答案 3 :(得分:1)

一个选项,如果文本真的是这种格式的一致性,那就是使用字符串操作而不是正则表达式:

source = ['<a href="https://twitter.com/download/android" rel="nofollow">Twitter for Android Tablets</a>', 
          '<a href="https://twitter.com/download/android" rel="nofollow">Twitter for  Android</a>',
          '<a href="http://foursquare.com" rel="nofollow">foursquare</a>', 'web',
          '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>',
          '<a href="http://blackberry.com/twitter" rel="nofollow">Twitter for BlackBerry</a>']

for i in source:
    print i.partition('>')[-1].rpartition('<')[0]

此代码找到第一个&#39;&gt;&#39;在字符串中,取出后面的所有内容,找到第一个&#39;&lt;&#39;在剩下的东西中,在此之前返回一切;例如,在第一个&#39;&gt;&#39;之间给你任何文字。最后一个&#39;&lt;&#39;

还有更多最小版本@Bakuriu发表评论,这可能比我的更好!

答案 4 :(得分:1)

这看起来不那么难看,应该同样有效:

import re
for i in source:
    print re.sub('(<.*?>)|(Twitter for\s+)', '', i);