2014-05-07 2 views
4

Je nettoie une série de sources à partir d'un flux Twitter. Voici un exemple des données:Meilleure façon d'utiliser re.sub

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' 

Le dernier est le code que j'ai qui fait le travail, mais est affreux. J'espérais qu'il y aurait une meilleure façon de le faire, y compris re.sub() ou une autre fonction qui pourrait être plus appropriée.

+3

s [s.index ('>') + 1: s.rindex ('<')] '. Au fait: au lieu de '. *?', J'utiliserais [^>] * '. – Bakuriu

+0

Nice codegolf! :) – TML

+0

@Bakuriu thx pour le commentaire. Quelle serait l'explication de '[^>] *'? – marbel

Répondre

2

ici sont des conseils pour améliorer votre code:

  • Utiliser la compilation regex afin que vous ne traitez pas la regex chaque fois que vous appliquez le regex,
  • utiliser des chaînes premières afin d'éviter toute interprétation de l'expression rationnelle chaîne en python,
  • utiliser une expression régulière qui prend quoi que ce soit, mais le caractère de balise de fermeture pour faire correspondre dans la balise
  • vous n'avez pas besoin de répéter la substitution car il est correspondant à chaque occurence sur la ligne par défaut

est ici un simple et un meilleur résultat:

>>> 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' 

NB: la meilleure solution pour votre cas d'utilisation serait @ suggestion de 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' 

qui ajoute pas de frais généraux importants et utilisations de base, opérations de chaînes rapides. Mais cette solution prend que ce qui est entre balises, au lieu de l'enlever, ce qui peut avoir des effets secondaires s'il y a des balises dans le <a> et </a> ou aucune étiquette du tout, à-dire qu'elle ne fonctionnera pas pour la chaîne web.Une solution contre aucun point du tout:

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

+1 pour la solution regex. Le bakuriu ne fonctionne pas à cause de l'affaire «web». Il n'a pas de '<' or '>'. Cependant, il est intéressant d'entendre à ce sujet car je suis extrêmement nouveau en python. – marbel

+0

Je vais utiliser ce qui suit: 'r = re.compile (r '(<[^>] +>) | (Twitter pour \ s +)')' afin de se débarrasser de la partie Twitter. – marbel

1

Une option, si le texte est vraiment dans cette cohérence d'un format, est d'utiliser simplement les opérations de chaîne au lieu de regex:

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] 

Ce code trouve le premier « > » dans la chaîne, prend tout après cela, trouve le premier '<' dans ce qui reste, et retourne tout avant cela; par exemple, vous donner un texte entre le premier '>' et le dernier '<'.

Il ya aussi la version beaucoup plus minimale @Bakuriu mis dans un commentaire, qui est probablement meilleur que le mien!

1

Cela semble moins laid pour moi et devrait fonctionner aussi bien:

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

Juste une autre alternative, en utilisant BeautifulSoup analyseur 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 
2

Si vous faites beaucoup de ceux-ci, l'utilisation une bibliothèque conçue pour gérer (X) HTML. lxml fonctionne bien, mais je suis plus familier avec le wrapper 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) 

Cela peut être un peu exagéré pour votre cas d'utilisation.