В программировании мы говорим об экранировании, когда нам нужно вставить в символьную строку символ, который может быть трактован интерпретатором или компилятором, как инструкция или часть синтаксиса, ей не являющаяся. Например, мы хотим уместить кавычки, но кавычки уже используюся для задания начала и конца самой строки.
Чаще всего для этого используется \
— обратный слеш.
Разберем пример с кавычкой
Неверно:
>>> print('don't ')
File "<stdin>", line 1
print('don't ')
^
SyntaxError: invalid syntax
Здесь кавычка посередине трактуется как конец строки, отсюда и ошибка синтаксиса.
Верно:
>>> print('don\'t ')
don't
Здесь бекслеш экранирует следующий за ним символ и он не заканчивает строку.
Похожая история случается с переносом строки. Мы знаем перенос строки как \n
— мы так пишем его в коде программы, но на самом деле, если мы заглянем в память компьютера, в место, где хранится эта строка — мы не увидим там \n
; начнем с того, что мы там не увидим вообще символов, а только байты, которые представляют эти символы. Но тем не менее, \
и n
— это байты 0x5c
и 0x6e
соответственно, а перенос строки — 0x0A
wikipedia. И в памяти будет он, 0x0A
. Это обусловлено тем, что мы не можем просто взять и вставить перенос строки в строку — это непечатный символ. Поэтому в тексте программы пишется \n
на его месте, отсюда и нужда в экранировании — чтобы иметь возможность отличать перенос строки от самой строки '\n'
В регулярных выражениях есть тоже символ экранирования, для создания конструкций типа \d
, \w
, \b
и так далее. Бекслеш экранирует следующий символ и говорит, что "это не просто буква, это спецзначение"
Из этого вытекает проблема, мы не знаем, на каком уровне экранирует бекслеш. На уровне регурярного выражения или на уровне строк питона? (ответ: на обоих, сначала на уровне питона, затем на уровне регулярных выражений, но от этого не легче). Например, мы вынуждены писать
regex = '\\d'
для захвата цифры. Сначала питон переваривает строку и видит в ней двойной бекслеш, понимает, что мы его экранировали и на самом деле там просто бекслеш
После этого регулярное выраженние видит \d
и понимает, что это цифра.
Регулярные выражения, уже и без того переусложненные и не человекочитаемые сущности, уложняются еще сильнее в тех случаях когда тебе нужно использовать в своем выражении бекслеш (достаточно часто)
Решением стал механизм, который называется raw string — строка, внутри которой \
не будет экранировать ничего:
>>> print('C:\Users\normal')
^^ это перенос строки
C:\Users\
ormal
>>> print(r'C:\Users\normal')
^ это означает, что строка — raw
C:\Users\normal
Это кстати приводит к такому интересному поведению:
>>> r'C:\Users\normal' (просто пишем строку без print)
'C:\\Users\\normal'
Это нормально, просто считай, что \\
— экранированный бекслеш, то есть на самом деле он там один, но для тебя отображается два. Можешь проверить сама: len(r'C:\Users\normal') == 15
Однако и это не панацея, бекслеш в raw строке не может быть в конце, так как питон будет думать, что это ты экранируешь закрывающую кавычку.
Все это относится к тексту кода, то есть ты не можешь написать
string = r'\'
или
string = r'something that ends with \'
но ты можешь написать
string = r'something that ends with' + '\\'