Python, supprimez tous les caractères non alphabétiques de la chaîne

90

J'écris un programme de comptage de mots MapReduce en python. Le problème est qu'il y a beaucoup de caractères non alphabétiques éparpillés dans les données, j'ai trouvé ce post Supprimant tout sauf les caractères alphanumériques d'une chaîne en Python qui montre une belle solution utilisant regex, mais je ne sais pas comment l'implémenter

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

J'ai peur de ne pas savoir comment utiliser la bibliothèque reou même l'expression régulière pour cette question. Je ne sais pas comment appliquer vcorrectement le motif regex à la chaîne entrante (ligne d'un livre) pour récupérer la nouvelle ligne sans aucun caractère non alphanumérique.

Suggestions?

KDecker
la source
vest une ligne entière d'un livre (en particulier moby dick), je vais mot par mot et non caractère par caractère. Ainsi, certains mots peuvent avoir un "," à la fin, donc "indignité" ne correspond pas à "indignité".
KDecker
Lolx - avez-vous eu le même exercice à la maison avant l'entrevue que moi? Trouvez les 50 mots les plus utilisés dans Moby Dick et indiquez leur fréquence. Je l'ai fait en C ++, IIRC
Mawg dit de réintégrer Monica le
1
@Mawg C'était un exercice dans mon cours de premier cycle "Cloud Computing".
KDecker

Réponses:

127

Utilisation re.sub

import re

regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', 'ab3d*E')
#Out: 'abdE'

Alternativement, si vous ne voulez supprimer qu'un certain jeu de caractères (comme une apostrophe peut convenir dans votre entrée ...)

regex = re.compile('[,\.!?]') #etc.
limasxgoesto0
la source
Hmm, je peux tout à fait le retrouver, mais qu'en est-il du modèle pour supprimer tous les non-alphanumériques à l'exclusion des espaces?
KDecker
1
Ajoutez simplement un espace dans votre classe de collection. ie ^a-zA-Z au lieu de juste^a-zA-Z
limasxgoesto0
Sauf si vous vous inquiétez également des nouvelles lignes, auquel cas a-zA-Z \n. J'essaie de trouver une expression régulière qui regrouperait les deux en un mais qui ne me donne pas \wou \Wne me donne pas le comportement souhaité. Vous devrez peut-être simplement ajouter \nsi c'est le cas.
limasxgoesto0
Ahh, le caractère de nouvelle ligne. C'est là que réside mes problèmes, je comparais mes résultats aux résultats donnés et j'étais toujours absent. Je pense que c'est mon problème! Merci // Hmm, je l'ai essayé avec le caractère de nouvelle ligne mêmes résultats, je pense qu'il y en a un autre qui me manque .. // Duhhh ... Majuscules et minuscules ... // Merci pour toute l'aide, fonctionne parfaitement maintenant!
KDecker
48

Si vous préférez ne pas utiliser regex, vous pouvez essayer

''.join([i for i in s if i.isalpha()])
Tad
la source
comment puis-je rejoindre cela? avec '' .join? l'impression ne reçoit qu'un objet filtre
PirateApp
Wow, c'est ce que je cherchais. Cela prend en compte les kanji, hiragana, katakana, etc. Kudos
root163
34

Vous pouvez utiliser la fonction re.sub () pour supprimer ces caractères:

>>> import re
>>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
'ABCabcdef'

re.sub (MATCH PATTERN, REMPLACE STRING, STRING TO SEARCH)

  • "[^a-zA-Z]+" - recherchez tout groupe de caractères qui ne sont PAS a-zA-z.
  • "" - Remplacez les caractères correspondants par ""
Kevin
la source
Notez que cela supprimera également les lettres accentuées: ãâàáéèçõ, etc.
Brad Ahrens
19

Essayer:

s = ''.join(filter(str.isalnum, s))

Cela prendra tous les caractères de la chaîne, ne conservera que les caractères alphanumériques et construira une chaîne à partir d'eux.

Don
la source
1
Cette réponse pourrait utiliser beaucoup plus d'explications et des liens vers la documentation pertinente.
pdoherty926 le
4

La méthode la plus rapide est regex

#Try with regex first
t0 = timeit.timeit("""
s = r2.sub('', st)

""", setup = """
import re
r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)

#Try with join method on filter
t0 = timeit.timeit("""
s = ''.join(filter(str.isalnum, st))

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""",
number = 1000000)
print(t0)

#Try with only join
t0 = timeit.timeit("""
s = ''.join(c for c in st if c.isalnum())

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)


2.6002226710006653 Method 1 Regex
5.739747313000407 Method 2 Filter + Join
6.540099570000166 Method 3 Join
PirateApp
la source
0

Il est conseillé d'utiliser le module PyPiregex si vous prévoyez de faire correspondre des classes de propriétés Unicode spécifiques. Cette bibliothèque s'est également avérée plus stable, en particulier pour la gestion de textes volumineux, et donne des résultats cohérents dans différentes versions de Python. Tout ce que vous avez à faire est de le maintenir à jour.

Si vous l'installez (en utilisant pip intall regexou pip3 install regex), vous pouvez utiliser

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

pour supprimer tous les blocs de 1 ou plusieurs caractères autres que les lettres Unicode de text. Voir une démo Python en ligne . Vous pouvez également utiliser "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))pour obtenir le même résultat.

En Python re, pour faire correspondre n'importe quelle lettre Unicode, on peut utiliser la [^\W\d_]construction ( Match any Unicode letter? ).

Ainsi, pour supprimer tous les caractères autres que des lettres, vous pouvez soit faire correspondre toutes les lettres et joindre les résultats:

result = "".join(re.findall(r'[^\W\d_]', text))

Ou supprimez tous les caractères autres que ceux correspondant à [^\W\d_]:

result = re.sub(r'([^\W\d_])|.', r'\1', text, re.DOTALL)

Voir la démo regex en ligne . Cependant , vous pouvez obtenir des résultats incohérents entre les différentes versions de Python car le standard Unicode évolue et le jeu de caractères correspondant \wdépendra de la version de Python. L'utilisation de la regexbibliothèque PyPi est fortement recommandée pour obtenir des résultats cohérents.

Wiktor Stribiżew
la source