2010-10-26 5 views
1

Voici ce que j'ai jusqu'à présentregex python trouver tous les groupes de mots

text = "Hello world. It is a nice day today. Don't you think so?" 
re.findall('\w{3,}\s{1,}\w{3,}',text) 
#['Hello world', 'nice day', 'you think'] 

La sortie souhaitée serait [ « Bonjour », « nice day », « aujourd'hui jour », « aujourd'hui ne pas ',' Ne 'vous', 'vous pensez']

Est-ce que cela peut être fait avec un simple motif regex?

+0

Qu'essayez-vous d'accomplir? – helpermethod

+0

Je voudrais regrouper tous les ensembles de 2 (dans ce cas) les mots qui sont 3 caractères ou plus comme dans la sortie désirée de l'exemple ci-dessus – tomfmason

Répondre

1
import itertools as it 
import re 

three_pat=re.compile(r'\w{3}') 
text = "Hello world. It is a nice day today. Don't you think so?" 
for key,group in it.groupby(text.split(),lambda x: bool(three_pat.match(x))): 
    if key: 
     group=list(group)  
     for i in range(0,len(group)-1): 
      print(' '.join(group[i:i+2])) 

# Hello world. 
# nice day 
# day today. 
# today. Don't 
# Don't you 
# you think 

Il ne sait pas à moi ce que vous voulez faire avec la ponctuation. D'une part, il semble que vous souhaitiez supprimer des points, mais que les guillemets simples soient conservés. Il serait facile d'appliquer la suppression des périodes, mais avant que je ne le fasse, pourriez-vous clarifier ce que vous voulez arriver à toute la ponctuation?

-1

Ceci est un excellent exemple de quand pas pour utiliser des expressions régulières pour l'analyse.

+3

c'est un excellent exemple quand ne pas poster une réponse. – SilentGhost

+0

bien y at-il une alternative simple? – tomfmason

1
map(lambda x: x[0] + x[1], re.findall('(\w{3,}(?=(\s{1,}\w{3,})))',text)) 

Peut être que vous pouvez réécrire le lambda pour plus courte (comme juste « + ») Et BTW 'ne fait pas partie de \ w ou \ de

+0

Ok, le moyen uber-neater: map ("". Rejoindre, re.findall ('(\ w {3,} (? = (\ S {1,} \ w {3,})))', texte)) – Lachezar

+0

Nice mais votre exemple me confirme que regex fera ressembler votre python à perl. – pyfunc

+0

Oui, tout ce qui utilise regexp est "très similaire" à Perl, car Perl est la base des expressions rationnelles actuelles - PCRE (Perl Compatible Reg Exp) - http://en.wikipedia.org/wiki/Regular_expression – Lachezar

1

Quelque chose comme ceci avec des contrôles supplémentaires pour les limites de la liste devrait faire:

>>> text = "Hello world. It is a nice day today. Don't you think so?" 
>>> k = text.split() 
>>> k 
['Hello', 'world.', 'It', 'is', 'a', 'nice', 'day', 'today.', "Don't", 'you', 'think', 'so?'] 
>>> z = [x for x in k if len(x) > 2] 
>>> z 
['Hello', 'world.', 'nice', 'day', 'today.', "Don't", 'you', 'think', 'so?'] 

>>> [z[n]+ " " + z[n+1] for n in range(0, len(z)-1, 2)] 
['Hello world.', 'nice day', "today. Don't", 'you think'] 
>>> 
+0

Parfois, regexes sont beaucoup plus de problèmes que ce qu'ils valent. +1 – jkerian

1

Il y a deux problèmes avec votre approche:

  1. ni \ w ni \ sm ponctuation des atches.
  2. Lorsque vous mettez en correspondance une chaîne avec une expression régulière à l'aide de findall, cette partie de la chaîne est consommée. La recherche du prochain match commence immédiatement après la fin du match précédent. Pour cette raison, un mot ne peut pas être inclus dans deux matches séparés.

Pour résoudre le premier problème, vous devez décider ce que vous entendez par mot. Les expressions régulières ne sont pas bonnes pour ce genre d'analyse. Vous voudrez peut-être regarder une bibliothèque d'analyse de langage naturel à la place.

Mais en supposant que vous puissiez trouver une expression régulière qui répond à vos besoins, pour résoudre le second problème, vous pouvez utiliser un lookahead assertion pour vérifier le deuxième mot. Cela ne renverra pas le match entier comme vous voulez mais vous pouvez au moins trouver le premier mot dans chaque paire de mots en utilisant cette méthode.

re.findall('\w{3,}(?=\s{1,}\w{3,})',text) 
        ^^^   ^
        lookahead assertion