Regex.sub() дает разные результаты re.sub()

Я работаю с Czech акцентированным текстом в Python 3.4.

Вызов re.sub() для выполнения подстановки с помощью regex по ударному предложению работает хорошо, но с использованием регулярного выражения, скомпилированного с re.compile(), а затем вызывается regex.sub().

Вот случай, когда я использую те же аргументы для re.sub() и regex.sub()

import re

pattern = r'(?<!\*)(Poplatn[ií]\w+ da[nň]\w+)'
flags = re.I|re.L
compiled = re.compile(pattern, flags)
text = 'Poplatníkem daně z pozemků je vlastník pozemku'
mark = r'**\1**' # wrap 1st matching group in double stars

print(re.sub(pattern, mark, text, flags))
# outputs: **Poplatníkem daně** z pozemků je vlastník pozemku
# substitution works

print(compiled.sub(mark, text))
# outputs: Poplatníkem daně z pozemků je vlastník pozemku
# substitution fails

Я считаю, что причина в акцентах, потому что для неадресного предложения re.sub() и regex.sub() работает одинаково.

Но мне кажется, что это ошибка, потому что передача тех же аргументов возвращает разные результаты, чего не должно быть. Эта тема осложняется различными платформами и локалями, поэтому она не может быть воспроизводимой в вашей системе. Вот скриншот моей консоли.

Python console

Видите ли вы ошибку в моем коде, или я должен сообщать об этом как ошибку?

Ответы

Ответ 1

Как Padraic Cunningham выяснил, на самом деле это не ошибка.

Однако это связано с ошибкой, с которой вы не столкнулись, и вам с использованием флага, который вы, вероятно, не должны использовать, поэтому я оставлю свой предыдущий ответ ниже, хотя его правильный ответ к вашей проблеме.


Здесь происходит недавнее изменение (где-то между 3.4.1 и 3.4.3 и между 2.7.3 и 2.7.8), которое влияет на это. До этого изменения вы даже не можете скомпилировать этот шаблон без повышения OverflowError.

Что еще более важно, почему вы используете re.L? Механизм re.L не означает "использовать правила Юникода для моей локали", это означает "использовать некоторые неуказанные правила, отличные от Юникода, которые действительно имеют смысл только для латинских производных локалей и могут работать неправильно в Windows". Или, как документы, поставьте его:

Сделайте \w, \w, \b, \b, \s и \s в зависимости от текущей локали. Использование этого флага не рекомендуется, так как механизм локали очень ненадежный, и он только обрабатывает одну "культуру" в любой момент; вместо этого следует использовать Unicode-сопоставление, которое по умолчанию используется в шаблонах Python 3 для Unicode (str).

См. ошибка # 22407 и связанный поток python-dev для недавнего обсуждения этого вопроса.

И если я удалю флаг re.L, теперь код теперь компилируется в порядке 3.4.1. (Я также получаю "правильные" результаты как на 3.4.1, так и на 3.4.3, но это просто совпадение: теперь я намеренно не передаю винтовой флаг и ввинчиваю его в первую версию и все равно случайно не передаю винтовой флаг и завинчивание его во втором, чтобы они соответствовали...)

Итак, даже если это была ошибка, есть хороший шанс, что он будет закрыт WONTFIX. Разрешение для # 22407 состояло в том, чтобы отказаться от шаблонов re.L для не bytes в 3.5 и удалить его в 3.6, поэтому я сомневаюсь, что кто-то позаботится об исправлении ошибок с ним сейчас. (Не говоря уже о том, что сам re теоретически уходит в пользу regex одного из этих десятилетий... и IIRC, regex также не рекомендуется использовать флаг L, если вы не используете шаблон bytes и re -compatible mode.)

Ответ 2

Последний аргумент в компиляции flags, если вы действительно используете flags=flags в re.sub, вы увидите одно и то же поведение:

compiled = re.compile(pattern, flags)
print(compiled)
text = 'Poplatníkem daně z pozemků je vlastník pozemku'
mark = r'**\1**' # wrap 1st matching group in double stars

r = re.sub(pattern, mark, text, flags=flags)

Четвертый аргумент re.sub равен count, поэтому вы видите разницу.

re.sub(pattern, repl, string, count = 0, flags = 0)

re.compile(pattern, flags = 0)