Skip to content

Instantly share code, notes, and snippets.

@lesha-co
Last active December 3, 2018 09:23
Show Gist options
  • Save lesha-co/8ea7a5f8c9aa252d33d9d7d0ea2b177d to your computer and use it in GitHub Desktop.
Save lesha-co/8ea7a5f8c9aa252d33d9d7d0ea2b177d to your computer and use it in GitHub Desktop.

Об экранировании

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

Чаще всего для этого используется \ — обратный слеш.

Разберем пример с кавычкой

Неверно:

>>> print('don't ')
  File "<stdin>", line 1
    print('don't ')
               ^
SyntaxError: invalid syntax

Здесь кавычка посередине трактуется как конец строки, отсюда и ошибка синтаксиса.

Верно:

>>> print('don\'t ')
don't

Здесь бекслеш экранирует следующий за ним символ и он не заканчивает строку.

Что ты видишь vs что происходит на деле

Похожая история случается с переносом строки. Мы знаем перенос строки как \n — мы так пишем его в коде программы, но на самом деле, если мы заглянем в память компьютера, в место, где хранится эта строка — мы не увидим там \n; начнем с того, что мы там не увидим вообще символов, а только байты, которые представляют эти символы. Но тем не менее, \ и n — это байты 0x5c и 0x6e соответственно, а перенос строки — 0x0A wikipedia. И в памяти будет он, 0x0A. Это обусловлено тем, что мы не можем просто взять и вставить перенос строки в строку — это непечатный символ. Поэтому в тексте программы пишется \n на его месте, отсюда и нужда в экранировании — чтобы иметь возможность отличать перенос строки от самой строки '\n'

Проблемы двойного экранирования

В регулярных выражениях есть тоже символ экранирования, для создания конструкций типа \d, \w, \b и так далее. Бекслеш экранирует следующий символ и говорит, что "это не просто буква, это спецзначение"

Из этого вытекает проблема, мы не знаем, на каком уровне экранирует бекслеш. На уровне регурярного выражения или на уровне строк питона? (ответ: на обоих, сначала на уровне питона, затем на уровне регулярных выражений, но от этого не легче). Например, мы вынуждены писать

regex = '\\d'

для захвата цифры. Сначала питон переваривает строку и видит в ней двойной бекслеш, понимает, что мы его экранировали и на самом деле там просто бекслеш

После этого регулярное выраженние видит \d и понимает, что это цифра.

Raw strting

Регулярные выражения, уже и без того переусложненные и не человекочитаемые сущности, уложняются еще сильнее в тех случаях когда тебе нужно использовать в своем выражении бекслеш (достаточно часто)

Решением стал механизм, который называется 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' + '\\'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment