2013-03-07 18 views
12

Korzystanie z Python 3.3. Chcę wykonać następujące czynności:Python: skuteczna metoda zastępowania akcentów (é do e), usuwanie [^ a-zA-Z d s] i niższe()

  • zastąpić specjalnych znaków alfabetycznych, takich jak e ostrego (E) i o daszkiem (O) z charakterem bazowej (O do O, na przykład)
  • usunąć wszystkie znaki z wyjątkiem alfanumeryczny a przestrzenie pomiędzy nimi znaków alfanumerycznych
  • nawrócony na małe

to, co mam tak daleko:

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) 

Jak mogę to poprawić? Wydajność jest dużym problemem, zwłaszcza, że ​​jestem obecnie wykonywanie operacji wewnątrz pętli:

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

Pliki w pytaniu około 200.000 znaków każdy.

+0

Nie mogę wysłać odpowiedzi, ponieważ to pytanie jest błędnie oznaczone jako duplikat, co absolutnie nie jest, ale może uda mi się umieścić moją odpowiedź w komentarzu. Dostarczone 'from unidecode import unidecode', zadanie zostanie wykonane przez' '' .join (c dla c w unidecode (mystring) .lower() jeśli ord (c) w zakresie (97,123) lub ord (c) == 32) .lstrip(). rstrip() '. Nie jest wymagane wyrażenie regularne. – mmj

Odpowiedz

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

Również sprawdzić unidecode

Co Unidecode zapewnia to środkowy drogowy: funkcja unidecode() wykonuje danych Unicode i stara się reprezentować go w znaki ASCII (czyli powszechnie wyświetlanych znaków między 0x00 i 0x7F), gdzie kompromisy podjęte podczas mapowania między dwoma zestawami znaków zostały wybrane , aby być blisko tego, co wybrałby człowiek z amerykańską klawiaturą.

Jakość wynikowej reprezentacji ASCII jest różna. Dla języków zachodniego pochodzenia powinien być między doskonałym a dobrym. Z drugiej strony transliteracja (tj. Przenoszenie, alfabetem rzymskim, wymowy wyrażonej przez tekst w innym systemie pisma) z języków , takich jak chiński, japoński lub koreański, jest bardzo złożonym problemem i ta biblioteka nawet nie próbuje zaadresować to. Rysuje linię przy mapowaniu znaków po znaku bez użycia kontekstu. Tak więc dobrą regułą jest to, że im dalej transliterowany skrypt pochodzi z alfabetu łacińskiego , tym gorsza będzie transliteracja.

Należy zauważyć, że ten moduł generalnie daje lepsze wyniki niż po prostu usuwanie akcentów ze znaków (można to zrobić w Pythonie z wbudowanymi funkcjami ). Opiera się on na ręcznym mapowaniu znaków, na przykład zawiera również przybliżenia ASCII dla symboli i niełacińskich alfabetów.

+0

To działa ładnie w celu usunięcia akcentów, ale chyba że zrobiłem coś nie tak, nie wydaje się, aby rozwiązać inne aspekty tego pytania. Doceń wprowadzenie do Unidecode. Ciekawa lektura, choć w moim przypadku nie zadziałałaby. – oyra

+1

to również działające def remove_accents (data): return unicodedata.normalize ('NFKD', data) .encode ('ASCII', 'ignore') –

+0

@RanvijaySachan Jaka jest różnica? – PascalVKooten

5

Można użyć 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,)) 

daje

123 foe bar 

Na dół-bok, trzeba będzie wymienić wszystkie specjalne znaki diakrytyczne, które chcesz Tłumaczyć.Metoda @ gnibbler wymaga mniejszego kodowania.

Po stronie góry, metoda str.translate powinna być dość szybka i może obsłużyć wszystkie twoje wymagania (zmniejszanie, usuwanie i usuwanie akcentów) w jednym wywołaniu funkcji po skonfigurowaniu table.


Nawiasem mówiąc, plik o 200k znaków nie jest zbyt duży. Więc byłoby bardziej wydajne odczytywanie całego pliku w pojedynczy plik str, a następnie przetłumaczenie go w jednym wywołaniu funkcji.

+0

Wydajność wydaje się identyczna z moim podejściem (0,96875 sekundy w obu przypadkach), ale jest to znacznie mniej hackish. Dzięki. W odniesieniu do tłumaczenia całego pliku naraz, muszę zachować formatowanie tekstu, ponieważ pracuję z plikami danych, takimi jak csv. – oyra

Powiązane problemy