2013-03-07 15 views
12

Utilizzo di Python 3.3. Voglio fare le seguenti operazioni:Python: metodo efficiente per sostituire gli accenti (é ae), rimuovere [^ a-zA-Z d s] e inferiore()

  • sostituire caratteri alfabetici speciali quali e acuto (é) e O circonflesso (O) con il carattere di base (o per o, per esempio)
  • rimuovere tutti i caratteri ad eccezione alfanumerico e spazi in mezzo alfanumerico caratteri
  • convertire in minuscolo

Questo è quello che ho finora:

mystring_modified = mystring.replace('\u00E9', 'e').replace('\u00F4', 'o').lower() 
alphnumspace = re.compile(r"[^a-zA-Z\d\s]") 
mystring_modified = alphnumspace.sub('', mystring_modified) 

Come posso migliorare? L'efficienza è una grande preoccupazione, soprattutto perché attualmente sto eseguendo le operazioni all'interno di un ciclo:

# Pseudocode 
for mystring in myfile: 
    mystring_modified = # operations described above 
    mylist.append(mystring_modified) 

I file in questione sono circa 200.000 caratteri ciascuno.

+0

Non riesco a pubblicare una risposta perché questa domanda è contrassegnata erroneamente come duplicata, il che non è assolutamente, ma forse riuscirò a inserire la mia risposta in un commento. Fornito 'da unidecode import unidecode', il lavoro verrà eseguito da' '' .join (c per c in unidecode (mystring) .lower() se ord (c) nell'intervallo (97,123) o ord (c) == 32) .lstrip(). rstrip() '. Non è necessaria alcuna regex. – mmj

risposta

23
>>> import unicodedata 
>>> s='éô' 
>>> ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')) 
'eo' 

controllare anche unidecode

Che Unidecode fornisce una via di mezzo: la funzione unidecode() batte dati Unicode e cerca di rappresentarlo in caratteri ASCII (vale a dire, i personaggi universalmente visualizzabili tra 0x00 e 0x7F), dove i compromessi dello vengono scelti quando la mappatura tra due set di caratteri viene scelta come per essere vicino a ciò che un essere umano con una tastiera americana sceglierebbe.

La qualità della rappresentazione ASCII risultante varia. Per le lingue di origine occidentale dovrebbe essere tra perfetto e buono. Dall'altra la traslitterazione a mano (cioè il trasporto, in lettere latine, della pronuncia espressa dal testo in altri sistemi di scrittura) delle lingue come cinese, giapponese o coreano è un problema molto complesso e questa libreria non tenta nemmeno per affrontarlo. Disegna la linea al mappatura carattere per carattere senza contesto. Quindi una buona regola empirica è che più lo script che stai traslitterando proviene dall'alfabeto latino , peggiore sarà la traslitterazione.

Si noti che questo modulo in genere produce risultati migliori rispetto semplicemente stripping accenti da caratteri (che può essere fatto in Python con funzioni integrate ). Si basa su mappature dei caratteri sintonizzati a mano che, ad esempio, contengono approssimazioni ASCII per i simboli e gli alfabeti non latini .

+0

Questo funziona bene per rimuovere gli accenti ma a meno che non ho fatto qualcosa di sbagliato non sembra affrontare gli altri aspetti della domanda. Apprezzo l'introduzione a Unidecode. Una lettura interessante, anche se non funzionerebbe nel mio caso. – oyra

+1

funziona anche def remove_accents (dati): return unicodedata.normalize ('NFKD', data) .encode ('ASCII', 'ignore') –

+0

@RanvijaySachan Qual è la differenza? – PascalVKooten

5

Si potrebbe utilizzare str.translate:

import collections 
import string 

table = collections.defaultdict(lambda: None) 
table.update({ 
    ord('é'):'e', 
    ord('ô'):'o', 
    ord(' '):' ', 
    ord('\N{NO-BREAK SPACE}'): ' ', 
    ord('\N{EN SPACE}'): ' ', 
    ord('\N{EM SPACE}'): ' ', 
    ord('\N{THREE-PER-EM SPACE}'): ' ', 
    ord('\N{FOUR-PER-EM SPACE}'): ' ', 
    ord('\N{SIX-PER-EM SPACE}'): ' ', 
    ord('\N{FIGURE SPACE}'): ' ', 
    ord('\N{PUNCTUATION SPACE}'): ' ', 
    ord('\N{THIN SPACE}'): ' ', 
    ord('\N{HAIR SPACE}'): ' ', 
    ord('\N{ZERO WIDTH SPACE}'): ' ', 
    ord('\N{NARROW NO-BREAK SPACE}'): ' ', 
    ord('\N{MEDIUM MATHEMATICAL SPACE}'): ' ', 
    ord('\N{IDEOGRAPHIC SPACE}'): ' ', 
    ord('\N{IDEOGRAPHIC HALF FILL SPACE}'): ' ', 
    ord('\N{ZERO WIDTH NO-BREAK SPACE}'): ' ', 
    ord('\N{TAG SPACE}'): ' ', 
    }) 
table.update(dict(zip(map(ord,string.ascii_uppercase), string.ascii_lowercase))) 
table.update(dict(zip(map(ord,string.ascii_lowercase), string.ascii_lowercase))) 
table.update(dict(zip(map(ord,string.digits), string.digits))) 

print('123 fôé BAR҉'.translate(table,)) 

cede

123 foe bar 

Sul rovescio della medaglia, dovrete elencare tutti i caratteri accentati speciali che si desidera tradurre.Il metodo @ gnibbler richiede meno codice.

Sul lato superiore, il metodo str.translate deve essere abbastanza veloce e può gestire tutti i requisiti (downcasing, eliminazione e rimozione di accenti) in una chiamata di funzione una volta impostato table.


A proposito, un file con caratteri 200K non è molto grande. Quindi sarebbe più efficiente leggere l'intero file in un singolo str, quindi tradurlo in una chiamata di funzione.

+0

Le prestazioni sembrano identiche al mio approccio (0,96875 secondi in entrambi i casi), ma questo è molto meno hackerato. Grazie. Riguardo alla traduzione dell'intero file in una volta, ho bisogno di preservare la formattazione del testo perché sto lavorando con file di dati come csv. – oyra

Problemi correlati