Regex - соответствует персонажу и всем его диакритическим вариациям (иначе говоря, нечувствителен к акценту)

Я пытаюсь сопоставить символ и все его возможные диакритические вариации (или нечувствительный к акценту) с регулярным выражением. Что я мог сделать, конечно:

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

но это не общее решение. Если я использую Unicode категории, такие как \pL Я не могу уменьшить соответствие конкретному символу, в этом случае e,

1 ответ

Решение

Обходной путь для достижения желаемой цели состоит в том, чтобы сначала использовать unidecode, чтобы избавиться от всех диакритических знаков, а затем просто сопоставить их с обычным e

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

Или в этом упрощенном случае

unidecode("é") == "e"

Другое решение, которое не зависит от unidecode-library, сохраняет unicode и дает больше контроля, вручную удаляя диакритические знаки следующим образом:

Используйте unicodedata.normalize(), чтобы превратить вашу входную строку в нормальную форму D (для разложенных), убедившись, что составные символы, такие как é превратиться в разложенную форму e\u301 (e + комбинированный острый акцент)

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

Затем удалите все кодовые точки, которые попадают в категорию Mark, Nonspacing (short Mn). Это все символы, которые сами по себе не имеют ширины и просто украшают предыдущий символ. Используйте unicodedata.category() для определения категории.

>>> stripped = "".join(c for c in normalized if unicodedata.category(c) != "Mn")
>>> stripped
'Hello'

Результат может быть использован в качестве источника для сопоставления с регулярным выражением, как в примере с unidecode выше. Вот все это как функция:

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")
Другие вопросы по тегам