Оператор escape Python Regex \ в подстановках и необработанных строках - PullRequest
7 голосов
/ 10 июня 2019

Я не понимаю логику в функционировании оператора scape \ в регулярном выражении python вместе с r 'необработанных строк. Некоторая помощь приветствуется.

код:

import re
text=' esto  .es  10  . er - 12 .23 with [  and.Other ] here is more ; puntuation'
print('text0=',text)
text1 = re.sub(r'(\s+)([;:\.\-])', r'\2', text)
text2 = re.sub(r'\s+\.', '\.', text)
text3 = re.sub(r'\s+\.', r'\.', text)
print('text1=',text1)
print('text2=',text2)
print('text3=',text3)

Теория гласит: символ обратной косой черты ('\') для обозначения специальных форм или разрешения использования специальных символов без вызова их специального значения.

И, как объясняет ссылка, приведенная в конце этого вопроса, r 'представляет собой необработанную строку, т. Е. Для символов нет особого значения, это как есть.

поэтому в приведенном выше регулярном выражении я бы ожидал, что text2 и text3 будут разными, поскольку текст подстановки - «.» в тексте 2, то есть точка, тогда как (в принципе) текст замещения в тексте 3 - это r '.' которая представляет собой необработанную строку, то есть строку в том виде, в котором она должна отображаться, обратную косую черту и точку. Но они приводят к тому же:

Результат:

text0=  esto  .es  10  . er - 12 .23 with [  and.Other ] here is more ; puntuation
text1=  esto.es  10. er- 12.23 with [  and.Other ] here is more; puntuation
text2=  esto\.es  10\. er - 12\.23 with [  and.Other ] here is more ; puntuation
text3=  esto\.es  10\. er - 12\.23 with [  and.Other ] here is more ; puntuation
#text2=text3 but substitutions are not the same r'\.' vs '\.'

Мне кажется, что r 'не работает одинаково ни в замещающей части, ни в обратном слэше. С другой стороны, моя интуиция говорит мне, что я что-то здесь упускаю.

РЕДАКТИРОВАТЬ 1: После комментария @Wiktor Stribiżew. Он указал, что (по его ссылке):

import re
print(re.sub(r'(.)(.)(.)(.)(.)(.)', 'a\6b', '123456'))
print(re.sub(r'(.)(.)(.)(.)(.)(.)', r'a\6b', '123456'))
# in my example the substitutions were not the same and the result were equal
# here indeed r' changes the results

, что дает:

ab
a6b

это озадачивает меня еще больше.

Примечание: Я прочитал этот вопрос переполнения стека о необработанных строках, который является супер полным. Тем не менее это не говорит о заменах

Ответы [ 2 ]

3 голосов
/ 10 июня 2019

Прежде всего,

replacement patterns ≠ regular expression patterns

Мы используем шаблон регулярных выражений для поиска совпадений, мы используем шаблон замены для заменынайдено совпадений с регулярным выражением.

Синтаксис шаблона замены в Python

Документы re.sub сбивают с толку, поскольку в них упоминаются обе escape-последовательности строк, которые могутиспользоваться в шаблонах замены (например, \n, \r) и escape-последовательностях регулярных выражений (\6), а также в тех, которые могут использоваться как в качестве регулярных выражений, так и в escape-последовательностях строк (\&).

IЯ использую термин regex escape-последовательность для обозначения escape-последовательности, состоящей из буквальной обратной косой черты + символа, то есть '\\X' или r'\X' и escape-последовательности строки дляОбозначим последовательность \ и символ или некоторую последовательность, которые вместе образуют действительную escape-последовательность строки .Они распознаются только в обычных строковых литералах .В необработанных строковых литералах вы можете экранировать только " (и именно поэтому вы не можете завершить необработанный строковый литерал \", но обратная реакция по-прежнему является частью строки).

Таким образом, в шаблоне замены вы можете использовать обратные ссылки:

re.sub(r'\D(\d)\D', r'\1', 'a1b')    # => 1
re.sub(r'\D(\d)\D', '\\1', 'a1b')    # => 1
re.sub(r'\D(\d)\D', '\g<1>', 'a1b')  # => 1
re.sub(r'\D(\d)\D', r'\g<1>', 'a1b') # => 1

Вы можете видеть, что r'\1' и '\\1' - это тот же шаблон замены, \1.Если вы используете '\1', он получит синтаксический анализ как escape-последовательность строки , символ с восьмеричным значением 001.Если вы забыли использовать префикс r с однозначной обратной ссылкой, проблем не возникнет, поскольку \g не является допустимой escape-последовательностью строки, и там в строке остается escape-символ \.Прочитайте документы, на которые я ссылался:

В отличие от стандартного C, все нераспознанные escape-последовательности остаются в строке без изменений, т. Е. В результате остается обратный слеш.

Таким образом, когда вы передаете '\.' в качестве строки замены, вы фактически отправляете комбинацию \. с двумя символами в качестве строки замены, и поэтому вы получаете \. в результате.

\ - это специальный символ в шаблоне замены Python

Если вы используете re.sub(r'\s+\.', r'\\.', text), вы получите тот же результат, что и в случаях text2 и text3, см. thisdemo .

Это происходит потому, что \\, две буквенные обратные косые черты, обозначают одну обратную косую черту в шаблоне замены.Если у вас нет группы 2 в шаблоне регулярных выражений, но в замене передано r'\2' для замены на комбинацию символов \ и 2, вы получите ошибку.

Таким образом, если у вас есть динамические определяемые пользователем шаблоны замещения, вам необходимо удвоить все обратные слеши в шаблонах замещения, которые должны передаваться в виде буквенных строк:

re.sub(some_regex, some_replacement.replace('\\', '\\\\'), input_string)
2 голосов
/ 10 июня 2019

Из Документ (мой акцент):

re.sub (pattern, repl, string, count = 0, flags = 0) Вернуть строку получен путем замены крайних левых непересекающихся вхождений шаблон в строке путем замены репл. Если шаблон не найден, Строка возвращается без изменений. repl может быть строкой или функцией; если это строка, все обратные слэши в ней обрабатываются. То есть \ n преобразуется в один символ новой строки, \ r преобразуется в возврат каретки и пр. Неизвестные экранированные буквы ASCII зарезервировано для будущего использования и рассматривается как ошибки. Другие неизвестные побеги такие как \ & оставлены в покое. Обратные ссылки, такие как \ 6, заменяются с подстрокой, сопоставленной группой 6 в шаблоне.

Аргумент repl - это не просто текст. Это также может быть имя функции или ссылка на позицию в группе (например, \g<quote>, \g<1>, \1).

Также с здесь :

В отличие от стандартного C, все нераспознанные escape-последовательности остаются в строка без изменений, т. е. обратный слеш остается в результате.

Поскольку . не является специальным escape-символом, '\.' совпадает с r'\.\.

...