#python #regex
#python #регулярное выражение
Вопрос:
Чтобы лучше понять, как r
и /
работают, я провел некоторое тестирование в IDLE Python. Результаты следующие:
>>> 11111111111111111111111111111111111111111
11111111111111111111111111111111111111111
>>> re.sub(r'?', r'?', '?ttt?')
'\?ttt\?'
>>> re.sub('?', r'?', '?ttt?')
'\?ttt\?'
>>> re.sub('\?', r'?', '?ttt?')
'\?ttt\?'
>>> re.sub(r'\?', r'?', '?ttt?')
'\??\?t\?t\?t\??\?'
>>> 222222222222222222222222222222222222222
222222222222222222222222222222222222222
>>> re.sub(r'?', r'?', '?ttt?')
'\?ttt\?'
>>> re.sub(r'?', '?', '?ttt?')
'\?ttt\?'
>>> re.sub(r'?', '\?', '?ttt?')
'\?ttt\?'
>>> re.sub(r'?', r'\?', '?ttt?')
'\?ttt\?'
>>> 333333333333333333333333
333333333333333333333333
>>> re.sub(r'(?)', r'11', '?ttt?')
'??ttt??'
>>> re.sub(r'(?)', '11', '?ttt?')
'x01x01tttx01x01'
>>>
Для первого аргумента re.sub()
:
-
Почему
r'?'
,'?'
'\?'
работают одинаково, в то время какr'\?'
работает по-разному? -
И почему
re.sub(r'\?', r'?', '?ttt?')
получается такой ожидаемый результат?
Для второго аргумента re.sub()
:
-
Почему это
r'?'
,'?'
'\?'
иr'\?'
все работают одинаково? -
Когда задействованы числа,
r
почти всегда необходимо, например,r'11'
и'11'
. Но я не понимаю, почему'1'
это то же самое, что'x01'
.
Комментарии:
1.
r
строки не имеют ничего общего с регулярными выражениями. Вы можете и должны изучить их поведение отдельно.2. Пожалуйста, задавайте только один вопрос за сообщение.
3. Вы должны начать с чтения
re
документации docs.python.org/3/library/re.html и руководство по регулярному выражению docs.python.org/3/howto/regex.html4. Некоторые из них тоже застали меня врасплох … хорошая задача для тех, кто думает, что знает синтаксис регулярных выражений Python!
Ответ №1:
Первое, что нужно понять, это то, как Python обрабатывает escape-последовательности:
Символ обратной косой черты () используется для экранирования символов, которые в противном случае имеют особое значение, таких как перевод строки, сама обратная косая черта или символ кавычки
Например, в '\?'
первая обратная косая черта пропускает вторую обратную косую черту, чтобы произвести только ?
.
В отличие от стандартного C, все нераспознанные escape-последовательности остаются в строке без изменений, т. Е. в результате остается обратная косая черта. (Это поведение полезно при отладке: если в escape-последовательности допущена ошибка, результирующий вывод легче распознать как нарушенный.) Также важно отметить, что управляющие последовательности, распознаваемые только в строковых литералах, попадают в категорию нераспознанных экранирований для байтовых литералов.
Итак, в '?'
, поскольку ?
это недопустимая escape-последовательность, Python оставляет ее просто ?
. Однако средства проверки стиля, такие как Pylint, будут помечать предупреждение «Аномальная обратная косая черта в строке».
При работе со строками, которые содержат много обратных косых черт, вы можете использовать синтаксис необработанных строк Python, чтобы избежать необходимости их экранирования:
>>> r'?' == '\?' == '?' # These are all equivalent
True
>>> r'?' == r'\?' # But r'\?' is different
False
>>> r'\?' == '\\?'
True
Числа также имеют особое значение при экранировании (они обрабатываются как восьмеричные):
>>> '141' == 'a'
True
Второе, что нужно понять, это то, как Python обрабатывает обратную косую черту в регулярных выражениях:
Возможно, наиболее важным метасимволом является обратная косая черта, . Как и в строковых литералах Python, за обратной косой чертой могут следовать различные символы для обозначения различных специальных последовательностей. Оно также используется для экранирования всех метасимволов, чтобы вы все еще могли сопоставлять их в шаблонах; например, если вам нужно сопоставить [ или , вы можете предварить их обратной косой чертой, чтобы удалить их особое значение: [ или \.
Например, в re.sub(r'?', r'?', '?ttt?')
первый аргумент r'?'
сообщает библиотеке регулярных выражений, что мы хотим выполнить поиск по ?
символу, а не рассматривать ?
его как квалификатор. Если бы мы не использовали необработанные строки, нам нужно было бы написать re.sub('\?', '\?', '?ttt?')
.
В отличие от этого, в re.sub(r'\?', r'?', '?ttt?')
первый аргумент r'\?'
сообщает библиотеке регулярных выражений, что мы хотим выполнить поиск по
символу, и ?
является специальным определителем регулярного выражения, который обрабатывает предыдущий символ как необязательный (в данном случае, заставляя шаблон всегда совпадать). Если бы мы не использовали необработанные строки, нам нужно было бы написать re.sub('\\?', '\?', '?ttt?')
.
Короче говоря, чтобы сопоставить буквальную обратную косую черту, нужно написать ‘\\’ как строку RE, потому что регулярное выражение должно быть \, и каждая обратная косая черта должна быть выражена как \ внутри обычного строкового литерала Python.
Да, регулярные выражения с необработанными строками и
становятся действительно запутанными, но это еще более запутанно без необработанных строк!
Дополнительные сведения: Способ обработки обратных косых черт во втором аргументе re.sub
немного отличается от первого аргумента. Библиотеке регулярных выражений по-прежнему необходимо предоставлять способ избежать обратных косых черт, иначе не было бы способа различать обратные ссылки, такие как r'1'
, и буквально заменять совпадения обратной косой чертой, за которой следует единица. Однако другой синтаксис регулярного выражения, такой как ?
, не нужно экранировать, потому что он не имеет особого значения во втором аргументе. Согласно документации для второго аргумента re.sub:
… любые экранирования обратной косой черты в нем обрабатываются. То есть n преобразуется в один символ новой строки, r преобразуется в возврат каретки и так далее. Неизвестные экранирования букв ASCII зарезервированы для будущего использования и рассматриваются как ошибки. Другие неизвестные экранирования, такие как amp;, оставлены в покое. Обратные ссылки, такие как 6, заменяются подстрокой, соответствующей группе 6 в шаблоне.
Таким образом, библиотека регулярных выражений обрабатывает re.sub(r'?', r'?', '?ttt?')
то же самое, что и re.sub(r'?', r'\?', '?ttt?')
, потому что ?
это неизвестная escape-последовательность регулярного выражения для второго аргумента (даже если это признанная escape-последовательность регулярного выражения для первого аргумента). Это отчасти похоже на то, как Python обрабатывает '?'
то же самое, что и '\?'
, но связано с тем, как библиотека регулярных выражений предпочитает обрабатывать обратные косые черты, а не с чем-либо, связанным с самим синтаксисом Python.
Комментарии:
1. Есть еще один вопрос, который меня озадачивает — как получилось
re.sub(r'?', r'?', '?ttt?')
иre.sub(r'?', r'\?', '?ttt?')
получить тот же результат? Я полагаю, что в результатеre.sub(r'?', r'\?', '?ttt?')
должно получиться'\\?ttt\\?'
вместо'\?ttt\?'
.2. @wbzy00 Я думаю, это потому, что
?
необходимо экранировать в первом аргументе вre.sub
, но во втором аргументе это не имеет особого значения (поэтому?
обрабатывается как неизвестная escape-последовательность и оставляется как есть). Я расширил свой ответ подробностями.