Python, rimuovi tutti i caratteri non alfabetici dalla stringa


93

Sto scrivendo un programma di conteggio parole MapReduce in python. Il problema è che ci sono molti caratteri non alfabetici disseminati nei dati, ho trovato questo post Spogliare tutto tranne i caratteri alfanumerici da una stringa in Python che mostra una bella soluzione usando regex, ma non sono sicuro di come implementarlo

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

Temo di non essere sicuro di come utilizzare la libreria reo anche le espressioni regolari per quella materia. Non sono sicuro di come applicare vcorrettamente il pattern regex alla stringa in arrivo (riga di un libro) per recuperare la nuova riga senza caratteri non alfanumerici.

Suggerimenti?


vè un'intera riga di un libro (in particolare moby dick), vado parola per parola non carattere per carattere. Quindi alcune parole potrebbero avere un "," alla fine, quindi "indignazione", non corrisponde a "indegnità".
KDecker


Lolx - hai fatto lo stesso esercizio a casa prima dell'intervista come me? Trova le 50 parole più usate in Moby Dick e segnala la loro frequenza. L'ho fatto in C ++, IIRC
Mawg dice di reintegrare Monica il

1
@Mawg Era un esercizio nella mia classe "Cloud Computing".
KDecker

Risposte:


130

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

In alternativa, se desideri rimuovere solo un determinato set di caratteri (poiché un apostrofo potrebbe andare bene nel tuo input ...)

regex = re.compile('[,\.!?]') #etc.

Hmm, posso rintracciarlo abbastanza, ma per quanto riguarda il modello per rimuovere tutti i non alfanumerici esclusi gli spazi?
KDecker

1
Basta aggiungere uno spazio nella tua classe di raccolta. cioè ^a-zA-Z invece di solo^a-zA-Z
limasxgoesto0

A meno che tu non sia preoccupato anche per le nuove righe, nel qual caso a-zA-Z \n. Sto cercando di trovare una regex che riunisca entrambi in uno, ma utilizzando \wo \Wnon mi dà il comportamento desiderato. Potrebbe essere necessario aggiungere solo \nse è così.
limasxgoesto0

Ahh, il carattere di nuova riga. Ecco dove risiedono i miei problemi, stavo confrontando i miei risultati con i risultati dati ed ero ancora fuori. Penso che sia il mio problema! Grazie // Hmm, l'ho provato con gli stessi risultati del carattere di nuova riga, penso che ce ne sia un altro che mi manca .. // Duhhh ... Maiuscolo e minuscolo ... // Grazie per tutto l'aiuto, funziona perfettamente ora!
KDecker

50

Se preferisci non usare regex, potresti provare

''.join([i for i in s if i.isalpha()])

come ci si unisce? con ".join? la stampa di s ottiene solo un oggetto filtro
PirateApp

1
Wow, questo è quello che stavo cercando. Questo tiene conto di kanji, hiragana, katakana, ecc. kudos
root163

34

Puoi usare la funzione re.sub () per rimuovere questi caratteri:

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

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

  • "[^a-zA-Z]+" - cerca qualsiasi gruppo di caratteri che NON sia a-zA-z.
  • "" - Sostituisci i caratteri corrispondenti con ""

Nota che questo rimuoverà anche le lettere accentate: ãâàáéèçõ, ecc.
Brad Ahrens

19

Provare:

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

Questo prenderà ogni carattere dalla stringa, manterrà solo quelli alfanumerici e costruirà una stringa da essi.


2
Questa risposta potrebbe utilizzare molte più spiegazioni e collegamenti alla documentazione pertinente.
pdoherty926

4

Il metodo più veloce è 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

0

Si consiglia di utilizzare il modulo PyPiregex se si prevede di abbinare classi di proprietà Unicode specifiche. Questa libreria ha anche dimostrato di essere più stabile, soprattutto nella gestione di testi di grandi dimensioni, e produce risultati coerenti in varie versioni di Python. Tutto quello che devi fare è tenerlo aggiornato.

Se lo installi (usando pip intall regexo pip3 install regex), puoi usare

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

per rimuovere tutti i blocchi di 1 o più caratteri diversi dalle lettere Unicode da text. Guarda una demo in linea di Python . Puoi anche usare "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))per ottenere lo stesso risultato.

In Python re, per abbinare qualsiasi lettera Unicode, si può usare il [^\W\d_]costrutto ( Match any Unicode letter? ).

Quindi, per rimuovere tutti i caratteri non composti da lettere, puoi abbinare tutte le lettere e unire i risultati:

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

Oppure rimuovi tutti i caratteri diversi da quelli corrispondenti a [^\W\d_]:

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

Guarda la demo regex online . Tuttavia , potresti ottenere risultati incoerenti tra varie versioni di Python perché lo standard Unicode si sta evolvendo e il set di caratteri abbinato \wdipenderà dalla versione di Python. L'utilizzo della regexlibreria PyPi è altamente raccomandato per ottenere risultati coerenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.