8
votes

Extraire des mots entiers

J'ai un grand ensemble de texte du monde réel que j'ai besoin de tirer des mots pour entrer dans un vérificateur orthographique. J'aimerais extraire autant de mots significatifs que possible sans trop de bruit. Je sais qu'il y a beaucoup de ninjas regex ici, j'espère que quelqu'un peut m'aider.

Actuellement, j'explète toutes les séquences alphabétiques avec '[A-Z] +' . C'est une approximation correcte, mais elle traîne beaucoup de déchets avec elle.

Idéalement Je voudrais que certaines regex (ne soient pas à être assez efficaces ou efficaces) qui extrait toutes les séquences alphabétiques délimitées par des séparateurs de mots naturels (tels que [/ -_ ,.: ] etc.), et ignore toutes les séquences alphabétiques avec des limites illégales.

Cependant, je serais également heureux de pouvoir simplement obtenir toutes les séquences alphabétiques qui ne sont pas adjacentes à un numéro. Donc, par exemple 'pie21' ' n'entraînerait pas ' pie ', mais ' http://foo.com ' extraire [ 'http', 'foo', 'com'] .

J'ai essayé lookahead et lookbehind assertions, mais ils ont été appliqués par caractère (donc par exemple re.findall ('(? retournerait ' pi ' quand je veux ne rien retourner). J'ai essayé d'envelopper la partie alpha en tant que terme ( (?: [A-Z] +) ) mais cela n'a pas aidé.

Plus de détails: Les données sont une base de données de messagerie, c'est donc surtout l'anglais normal avec des nombres normaux, mais il y a occasionnellement des cordes de déchets comme gihq4nwl0s5scgbdd40zxe5idp13tynea et AC7A21C0 que j'aimerais ignorer complètement. Je suppose une séquence alphabétique avec un nombre en elle est des ordures.


1 commentaires

Mieux vaut utiliser des chaînes brutes avec des regexes. \ d arrive à fonctionner, mais d'autres séquences d'échappement échoueront, et cela peut être difficile à déboguer.


4 Réponses :


18
votes

Si vous vous limitez aux lettres ASCII, utilisez (avec le jeu d'options CODE> RE.I CODE>)

\b[^\W\d_]+\b


5 commentaires

Cela ressemble exactement à ce que je veux, mais je ne peux pas obtenir le ballon \ b s pour fonctionner. Avec texte défini comme une phrase normale, re.findall ('\ b [a-z] + \ b', texte, re.i) ne renvoie rien. Peu importe ce que j'ai mis sur les crochets (ou en utilisant recherche ou correspondant ) il ne semble pas aider non plus. Utilisation de \ B me donne des résultats, mais enregistre le premier et le dernier caractère de chaque mot. Aussi paresseux que ça sonne, je suis trop fatigué pour prendre un nouveau concept en ce moment; Avez-vous des chances que vous sachiez pourquoi cela ne fonctionne pas? Ou que vous pouvez poster un exemple littéral de la façon dont vous l'utiliseriez dans ce cas?


C'est exactement pourquoi j'ai écrit mon commentaire à votre question. Si vous n'utilisez pas de chaînes brutes ( r "\ b [a-z] \ b" ), le \ b sera interprété comme un caractère arrière.


OOOOOOOOOOOOOH, c'est ce que vous vouliez dire :). Désolé, il est maintenant 5h30 ici et je n'allais jamais faire ce lien. Ajoutez simplement le R et ça marche un régal! Merci Monsieur.


En général, cela fonctionne, mais cela échouera sur des mots avec des caractères spéciaux (par exemple wenn bei beförderungen schäden )


@yekta: non si vous compilez la rééglementation à l'aide du re.unicode ou re.locale option. Je devrais ajouter ça à ma réponse.



3
votes

Êtes-vous familiarisé avec limites de mots? ( \ b ). Vous pouvez extraire des mots à l'aide du \ b autour de la séquence et correspondant à l'alphabet dans: xxx

par exemple, cela saisira des mots entiers mais s'arrêtera à des jetons tels que des traits d'union , périodes, semi-couches, etc.

Vous pouvez la séquence \ b et d'autres, sur le manuel de Python

Modifier aussi, si vous souhaitez environ un numéro ou le match précédent , vous pouvez utiliser un look négatif / derrière: xxx


3 commentaires

Selon la réponse de Tim, \ b sonne comme ce que je veux, mais ça ne joue pas bien. Des idées? J'ai déjà essayé la lunette et regarder les regards avant, mais ils semblent correspondre à tous les personnages jusqu'à ce que le personnage adjacente à un nombre, et n'ignore donc pas complètement les mots avec des chiffres. En outre, il se plaint de regarder des motifs de largeur fixe avec ceux-ci + s.


@ Pie21: utilisez ensuite une correspondance à un chiffre. Nous ne nous soucions pas du nombre de numéros post / précédent, juste qu'il y a un chiffre. Exemple


J'ai eu ce travail [re.findall (r "\ b ([a-za-z] +) \ b", contenu, re.i)] mais il ne semble pas être éliminé en avant et à back-slashes. Voici quelques mots qui sont sortis: '[endif]', '$', '8', '/ petit', '/ li'



2
votes

Qu'en est-il de: xxx

Notez que:

  • Split explose votre chaîne en candidats potentiels => renvoie une liste de "mots potentiels"
  • Set fait filtrer unicity => Transforme la liste en jeu, supprimant ainsi les entrées apparaissant plus d'une fois. Cette étape n'est pas obligatoire.
  • Filtre réduit le nombre de candidats: prend une liste, applique une fonction de test à chaque élément et renvoie une liste de l'élément qui succédant au test. Dans notre cas, la fonction de test est "anonyme"
  • lambda: fonction anonyme, prenant un article et vérifiant si c'est un mot (lettres majuscules ou inférieures uniquement)

    edit : Ajout de certaines explications


1 commentaires

Laid tel qu'il est, ça marche! À votre santé! Cependant, puis-je poser une préférence supplémentaire: puisque je ne parle pas Lambda ou filtrer, est-il un moyen de faire ce genre de chose avec re.finditer () ? J'ai besoin de suivre les indices de début et de fin de chaque match dans le texte.



0
votes

exemple de code xxx

ou xxx


0 commentaires