2013-06-13 13 views
7

Jaki jest najprostszy sposób na usunięcie modyfikatorów znaków z łańcucha unicode w Pythonie?Usuwanie modyfikatorów znaków Unicode

Na przykład:

Arthur powinien stać Arthur

Próbowałem docs, ale nie mogłem znaleźć niczego, co robi.

Odpowiedz

6

Spróbuj

import unicodedata 
a = u"STRING GOES HERE" # using an actual string would break stackoverflow's code formatting. 
u"".join(x for x in a if not unicodedata.category(x).startswith("M")) 

To usunie wszystkie znaki sklasyfikowane jako znaki, które jest to, co myślę, że chcesz. Ogólnie rzecz biorąc, możesz uzyskać kategorię postaci z unicodedata.category.

+3

+1. Lepiej jednak użyć '.startswith ('M')' zamiast '' M 'in' tutaj. Począwszy od wersji 6.1, nie ma podkategorii "M" w żadnej kategorii, ale nie ma żadnej zasady, która mówi, że nie może być w przyszłości. – abarnert

+0

@abarnert: Więc mówisz, że lepiej użyć czegoś, co może pęknąć w przyszłości? – martineau

+0

@martineau: Nie, lepiej użyć czegoś, co nie będzie w przyszłości łamać. Jeśli dodana zostanie podkategoria kategorii "M", będzie ona dotyczyła łączenia znaków. Jeśli zostanie dodana nowa podkategoria "M" innej kategorii, nie będzie ona dotyczyła łączenia znaków. Tak więc właściwą zasadą łączenia znaków jest 'cat.startswith ('M')', a nie ''M' in cat'. (Nie jest to prawdopodobne, że pojawią się, ponieważ nie dodali żadnych nowych podkategorii, które dzielą litery używane przez główne kategorie, i opróżnili jedyną istniejącą, "LC". Ale nie ma nic złego w robieniu tego, najmniej potencjalna korzyść.) – abarnert

5

Można też użyć r'\p{M}', który jest obsługiwany przez regex module:

import regex 

def remove_marks(text): 
    return regex.sub(ur"\p{M}+", "", text) 

Przykład:

>>> print s 
A͋͠r͍̞̫̜t̼̭͞h́u̡̙̞̘rͬͣ̐ͮ 
>>> def remove_marks(text): 
...  return regex.sub(ur"\p{M}+", "", text) 
...  
... 
>>> print remove_marks(s) 
Arthur 

zależności od użytkową przypadku whitelist podejście może być lepsza np ograniczyć tylko wejście do znaków ASCII:

>>> s.encode('ascii', 'ignore').decode('ascii') 
u'Arthur' 

Wynik może zależeć od normalizacji Unicode użytej w tekście.

+0

Dobra uwaga na temat normalizacji - jeden lub więcej znaków może się składać na jedną z liter, w takim przypadku stracisz tę literę. Ale możesz to rozwiązać, wykonując 'unicoredata.normalize ('NFD', s) .encode ('ascii', 'ignore'). Decode ('ascii')'. (Zamiast tego możesz użyć "NFKD", w zależności od tego, czy spodziewasz się uzyskać coś w rodzaju U + 2160 ("Ⅰ"), a jeśli tak, czy chcesz traktować je jako kompatybilny odpowiednik U + 0049 ('I') lub pomiń je.) – abarnert

Powiązane problemy