Регулярное выражение для замены нечувствительных к акценту в Python

В Python 3 я хотел бы иметь возможность использовать re.sub() "нечувствительным к акценту" способом, как мы можем сделать с re.I флаг для замены без учета регистра.

Может быть что-то вроде re.IGNOREACCENTS флаг:

original_text = "¿It's 80°C, I'm drinking a café in a cafe with Chloë。"
accent_regex = r'a café'
re.sub(accent_regex, 'X', original_text, flags=re.IGNOREACCENTS)

Это привело бы к "" Это 80°C, я пью X в X с Хлоей。" (обратите внимание, что на"Chloë"все еще есть акцент) вместо"¿Это 80°C, я пью X в кафе с Хлоей in в реальном питоне.

Я думаю, что такого флага не существует. Так что будет лучшим вариантом для этого? С помощью re.finditer а также unidecode на обоих original_text а также accent_regex а затем заменить, разделив строку? Или изменив все символы в accent_regex по их акцентированным вариантам, например: r'[cç][aàâ]f[éèêë]'?

3 ответа

Решение

unidecode часто упоминается для удаления акцентов в Python, но это также делает нечто большее: он конвертирует '°' в 'deg', который не может быть желаемым результатом.

unicodedata кажется, достаточно функциональности для удаления акцентов.

С любым рисунком

Этот метод должен работать с любым шаблоном и любым текстом.

Вы можете временно удалить акценты как из текста, так и из регулярных выражений. Информация о матче от re.finditer() (начальный и конечный индексы) могут быть использованы для изменения исходного текста с акцентом.

Обратите внимание, что совпадения должны быть отменены, чтобы не изменять следующие индексы.

import re
import unicodedata

original_text = "I'm drinking a 80° café in a cafe with Chloë, François Déporte and Francois Deporte."

accented_pattern = r'a café|François Déporte'

def remove_accents(s):
    return ''.join((c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn'))

print(remove_accents('äöüßéèiìììíàáç'))
# aoußeeiiiiiaac

pattern = re.compile(remove_accents(accented_pattern))

modified_text = original_text
matches = list(re.finditer(pattern, remove_accents(original_text)))

for match in matches[::-1]:
    modified_text = modified_text[:match.start()] + 'X' + modified_text[match.end():]

print(modified_text)
# I'm drinking a 80° café in X with Chloë, X and X.

Если шаблон это слово или набор слов

Вы могли бы:

  • удалите акценты из слов в шаблоне и сохраните их в наборе для быстрого поиска
  • ищите каждое слово в вашем тексте с \w+
  • убрать акценты со слова:
    • Если это соответствует, замените на X
    • Если это не соответствует, оставьте слово нетронутым

import re
from unidecode import unidecode

original_text = "I'm drinking a café in a cafe with Chloë."

def remove_accents(string):
    return unidecode(string)

accented_words = ['café', 'français']

words_to_remove = set(remove_accents(word) for word in accented_words)

def remove_words(matchobj):
    word = matchobj.group(0)
    if remove_accents(word) in words_to_remove:
        return 'X'
    else:
        return word

print(re.sub('\w+', remove_words, original_text))
# I'm drinking a X in a X with Chloë.

Вы можете использовать Unidecode:

$ pip install unidecode

В вашей программе:

from unidecode import unidecode

original_text = "I'm drinking a café in a cafe."
unidecoded_text = unidecode(original_text)
regex = r'cafe'
re.sub(regex, 'X', unidecoded_text)

Вместо того, чтобы убирать акценты, мне нужно было сохранить акценты в тексте, тогда я использовал следующий код:

      accents_dic = {
'A': '(A|Á|À|Â|Ã)',
'E': '(E|É|È)',
'I': '(I|Í|Ï)',
'O': '(O|Ó|Ô|Õ|Ö)',
'U': '(U|Ú|Ü)',
'C': '(C|Ç)'
}
def define_regex_name(name):
    for i, j in accents_dic.items():
        name = re.sub(i,j,name)
    return re.compile(name, re.IGNORECASE)
Другие вопросы по тегам