Смущен обратной косой чертой в регулярных выражениях
Я путаюсь с обратной косой чертой в регулярных выражениях. В пределах регулярного выражения a \
имеет особое значение, например. \d
означает десятичную цифру. Если вы добавили обратную косую черту перед обратным слэшем, это особое значение теряется. В regex-howto можно прочитать:
Возможно, самым важным метасимволом является обратная косая черта, \
. Как и в строковых литералах Python, обратная косая черта может сопровождаться различными символами для сигнализации различных специальных последовательностей. Его также использовали, чтобы избежать всех метасимволов, чтобы вы все еще могли сопоставлять их с шаблонами; например, если вам нужно соответствовать [
или \
, вы можете перед ними обратную косую черту, чтобы удалить их особый смысл: \[
или \\
.
Итак print(re.search('\d', '\d'))
дает None
, потому что \d
соответствует любой десятичной цифре, но в \d
нет ни одного.
Теперь я ожидаю, что print(re.search('\\d', '\d'))
будет соответствовать \d
, но ответ по-прежнему None
.
Только print(re.search('\\\d', '\d'))
дает в качестве вывода <_sre.SRE_Match object; span=(0, 2), match='\\d'>
.
Есть ли у кого-нибудь объяснения?
Ответы
Ответ 1
Путаница связана с тем, что символ обратной косой черты \
используется в качестве выхода на двух разных уровнях. Во-первых, сам интерпретатор Python выполняет замены для \
до того, как модуль re
увидит вашу строку. Например, \n
преобразуется в символ новой строки, \t
преобразуется в символ табуляции и т.д. Чтобы получить фактический символ \
, вы также можете экранировать его, поэтому \\
дает один \
. ] характер. Если символ, следующий за \
, не является распознанным escape-символом, тогда \
обрабатывается как любой другой символ и проходит через него, но я не рекомендую зависеть от этого. Вместо этого всегда избегайте своих \
персонажей, удваивая их, то есть \\
.
Если вы хотите увидеть, как Python расширяет ваши строки, просто распечатайте строку. Например:
s = 'a\\b\tc'
print(s)
Если s
является частью агрегированного типа данных, например, список или кортеж, и если вы напечатаете этот агрегат, Python заключит строку в одинарные кавычки и включит escape-символы \
(в канонической форме), так что будьте внимательны, как печатается ваша строка. Если вы просто напечатаете строку в кавычках в интерпретаторе, она также отобразит ее в кавычках с символами \
.
Как только вы узнаете, как кодируется ваша строка, вы можете подумать, что с ней будет делать модуль re
. Например, если вы хотите экранировать \
в строке, передаваемой в модуль re
, вам нужно будет передать \\
в re
, что означает, что вам нужно будет использовать \\\\
в вашем цитируемом Python строка. Строка Python будет заканчиваться на \\
, а модуль re
будет обрабатывать это как один литеральный символ \
.
Альтернативный способ включить символы \
в строки Python - это использовать необработанные строки, например, r'a\b'
эквивалентен "a\\b"
.
Ответ 2
Символ r перед регулярным выражением в вызове search() указывает, что регулярное выражение является необработанной строкой. Это позволяет использовать обратную косую черту в регулярном выражении в качестве обычных символов, а не в escape-последовательности символов. Позвольте мне объяснить...
Прежде чем метод поиска re module обрабатывает переданные ему строки, интерпретатор Python выполняет первоначальный проход по строке. Если в строке присутствуют обратные слэши, интерпретатор Python должен решить, является ли каждый из них частью escape-последовательности Python (например,\n или \t) или нет.
Примечание: на данный момент Python не заботится о том, является ли '\' мета-символом регулярного выражения.
Если за "\" следует распознанный escape-символ Python (t, n и т.д.), То обратная косая черта и escape-символ заменяются фактическим Unicode или 8-битным символом. Например, '\ t' будет заменено символом ASCII для табуляции. В противном случае он передается и интерпретируется как символ '\'.
Подумайте о следующем.
>>> s = '\t'
>>> print ("[" + s + "]")
>>> [ ] // an actual tab character after preprocessing
>>> s = '\d'
>>> print ("[" + s + "]")
>>> [\d] // '\d' after preprocessing
Иногда мы хотим включить в строку символьную последовательность, которая включает '\', без интерпретации Python как escape-последовательность. Для этого мы избегаем "\" с помощью "\". Теперь, когда Python видит "\", он заменяет две обратные косые черты одним символом "\".
>>> s = '\\t'
>>> print ("[" + s + "]")
>>> [\t] // '\t' after preprocessing
После того, как интерпретатор Python передаст обе строки, они будут переданы в метод поиска re module. Метод поиска анализирует строку регулярного выражения, чтобы определить метасимволы регулярного выражения.
Теперь '\' также является специальным метасимволом регулярного выражения и интерпретируется как один, ЕСЛИ он не экранируется во время выполнения метода re search().
Рассмотрим следующий вызов.
>>> match = re.search('a\\t','a\\t') //Match is None
Здесь совпадений нет. Почему? Давайте посмотрим на строки после того, как интерпретатор Python сделает это.
String 1: 'a\t'
String 2: 'a\t'
Так почему же матч равен None? Когда search() интерпретирует строку 1, поскольку это регулярное выражение, обратный слеш интерпретируется как метасимвол, а не как обычный символ. Обратная косая черта в строке 2, однако, отсутствует в регулярном выражении и уже была обработана интерпретатором Python, поэтому она интерпретируется как обычный символ.
Поэтому метод search() ищет в строке 'a\t' escape-t, которые не совпадают.
Чтобы исправить это, мы можем сказать, что метод search() не должен интерпретировать '\' как метасимвол. Мы можем сделать это, избежав этого.
Рассмотрим следующий вызов.
>>> match = re.search('a\\\\t','a\\t') // Match contains 'a\t'
Опять же, давайте посмотрим на строки после того, как интерпретатор Python прошел.
String 1: 'a\\t'
String 2: 'a\t'
Теперь, когда метод search() обрабатывает регулярное выражение, он видит, что второй обратный слеш экранируется первым и не должен рассматриваться как метасимвол. Поэтому он интерпретирует строку как 'a\t', что соответствует строке 2.
Альтернативный способ сделать так, чтобы search() рассматривал символ "\", - поместить r перед регулярным выражением. Это говорит интерпретатору Python НЕ предварительно обрабатывать строку.
Учтите это.
>>> match = re.search(r'a\\t','a\\t') // match contains 'a\t'
Здесь интерпретатор Python не изменяет первую строку, но обрабатывает вторую строку. Строки, переданные функции search():
String 1: 'a\\t'
String 2: 'a\t'
Как и в предыдущем примере, search интерпретирует '\' как отдельный символ '\', а не как метасимвол, поэтому соответствует строке 2.
Ответ 3
Собственный синтаксический анализ Python (частично) на вашем пути.
Если вы хотите увидеть, что видит re
, введите
print '\d'
print '\\d'
print '\\\d'
в командной строке Python. Вы видите, что \d
и \\d
оба результата приводят к \d
, причем последний обрабатывается парсером строк Python.
Если вы хотите избежать каких-либо проблем с ними, используйте необработанные строки, как было предложено re module documentation: r'\\d'
приведет к \\d
, видимый модулем RE.