2016-03-03 9 views
5

Ich versuche, ein Zeichen und alle seine möglichen diakritischen Variationen (auch Akzent-unempfindlich) mit einem regulären Ausdruck übereinstimmen. Was ich natürlich tun könnte, ist:Regex - passen Sie ein Zeichen und alle seine diakritischen Variationen (auch Akzent-unempfindlich)

re.match(r"^[eēéěèȅêęëėẹẽĕȇȩę̋ḕḗḙḛḝė̄]$", "é") 

aber das ist keine allgemeine Lösung. Wenn ich Unicode-Kategorien wie \pL verwende, kann ich die Übereinstimmung nicht auf ein bestimmtes Zeichen reduzieren, in diesem Fall e.

+0

Does Python REGEX die * POSIX-Zeichen Äquivalenz * Spiel unterstützen? Das ist so einfach wie '[= e =]' - aber es entspricht auch seinen großgeschriebenen Äquivalenten, die in Ihrem Fall zu viel sein können. Dies könnte mit "(?! \ U)" umgehen, obwohl dies wiederum Ihre Regex benötigt, um auch Großbuchstaben für alle Unicode-Zeichen zu unterstützen. – usr2564301

Antwort

12

Eine Abhilfe das gewünschte Ziel zu erreichen, wäre unidecode zu verwenden alle diakritischen Zeichen zuerst loszuwerden, und dann agains der regulären e

nur passen
re.match(r"^e$", unidecode("é")) 

Oder in diesem vereinfachten Fall

unidecode("é") == "e" 

Eine andere Lösung, die nicht von der Unidecode-Bibliothek abhängt, Unicode erhält und mehr Kontrolle bietet, ist das manuelle Entfernen der Diacri wie folgt Tics:

Verwenden unicodedata.normalize() Ihr Eingabestring in Normalform D (für zerlegten) zu drehen, wie é sicherstellen, dass zusammengesetzte Zeichen zu bekommen in die decomposite Form gedreht e\u301 (e + AKUT KOMBINATION)

>>> input = "Héllô" 
>>> input 
'Héllô' 
>>> normalized = unicodedata.normalize("NFKD", input) 
>>> normalized 
'He\u0301llo\u0302' 

Entfernen Sie dann alle Codepunkte, die in die Kategorie Mark, Nonspacing (kurz Mn) fallen. Das sind alles Charaktere, die selbst keine Breite haben und nur das vorherige Zeichen verzieren. Verwenden Sie unicodedata.category(), um die Kategorie zu bestimmen.

Das Ergebnis kann als Quelle für Regex-Matching verwendet werden, genau wie im obigen Beispiel. Hier ist das Ganze als eine Funktion:

def remove_diacritics(text): 
    """ 
    Returns a string with all diacritics (aka non-spacing marks) removed. 
    For example "Héllô" will become "Hello". 
    Useful for comparing strings in an accent-insensitive fashion. 
    """ 
    normalized = unicodedata.normalize("NFKD", text) 
    return "".join(c for c in normalized if unicodedata.category(c) != "Mn")