Почему 3 обратной косой черты равны 4 в строке Python?

90

Подскажите почему '?\\\?'=='?\\\\?'дает True? Это сводит меня с ума, и я не могу найти разумного ответа ...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']
kozooh
источник
8
Последний не убегает ни от чего, поэтому в конечном итоге сбегает сам,
Падрайк Каннингем,
1
Не нужно включать list()даже:>>> '?\\\?' '?\\\\?'
daboross 01
@PadraicCunningham Это не «само побег». Что это хотя бы значит?
user253751 01
Забавно, но причина в том, что они оба равны двум
обратным слешам
@immibis, это именно то, что происходит. Вы знаете разницу между repr и str? Попробуйте напечатать оба с одной обратной косой чертой в строке, и все станет ясно
Падрайк Каннингем

Ответы:

84

В основном потому, что python немного снисходителен к обработке обратной косой черты. Цитата из https://docs.python.org/2.0/ref/strings.html :

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

(Выделено в оригинале)

Следовательно, в Python три обратных косых черты не равны четырем, а то, что, когда вы следуете за обратной косой чертой с таким символом, как ?, два вместе проходят как два символа, потому что \?это не распознанная escape-последовательность.

Дэниел Мартин
источник
6
Это противоположность снисходительности. Снисходительность - это поведение большинства остальных: «если вы сделаете обратную косую черту не нужному символу , обратная косая черта ничего не сделает». Вместе с другим соглашением (обратная косая черта может сделать их особенными, но обратная косая черта всегда делает ее не особенной), вы получаете очень приятное свойство: вы можете безопасно удалить строку, удаляя все знаки препинания, не зная, какие символы являются особыми. interpeted - свойство, которого не хватает Python.
hobbs 01
24
Нет, противоположность снисходительности - это вызвать ошибку при использовании нераспознанного escape-символа обратной косой черты. (Как и почти все скомпилированные языки. Помните, что обработка строк в Python в основном «похожа на C, за исключением того, что мы не взрываемся, когда передаются недопустимые экранирования обратной косой черты»). Кроме того, в строке, на каком бы языке ни был язык, есть только два символа, которые нужно экранировать. - все, что вы используете в качестве разделителя, и обратную косую черту. Я не понимаю аргумента, что трудно запомнить и то, и другое.
Дэниел Мартин
@DanielMartin есть некоторые языки, в которых разделитель функционирует как собственный escape-символ (например, 'escape''d'). Там вам даже не нужно запоминать других персонажей!
SztupY 01
1
Ой, подождите, я думаю, стандартный паскаль тоже использовал эту систему - см. Nyx.net/~gthompso/self_pasc.txt
Дэниел Мартин
1
@DanielMartin SQL тоже.
Random832
30

Это связано с тем, что обратная косая черта действует как escape-символ для символа (ов), следующего за ним, если комбинация представляет собой допустимую escape-последовательность. Здесь перечислены около дюжины управляющих последовательностей . Они включают в себя очевидные, такие как новая строка \n, горизонтальная табуляция \t, возврат каретки \rи более непонятные, такие как использование именованных символов Unicode \N{...}, например, \N{WAVY DASH}которые представляют символ Unicode \u3030. Однако ключевым моментом является то, что если escape-последовательность неизвестна, последовательность символов остается в строке как есть.

Частично проблема может заключаться в том, что вывод интерпретатора Python вводит вас в заблуждение. Это связано с тем, что при отображении символы обратной косой черты экранируются. Однако, если вы напечатаете эти строки, вы увидите, что лишние обратные косые черты исчезнут.

>>> '?\\\?'
'?\\\\?'
>>> print('?\\\?')
?\\?
>>> '?\\\?' == '?\\?'    # I don't know why you think this is True???
False
>>> '?\\\?' == r'?\\?'   # but if you use a raw string for '?\\?'
True
>>> '?\\\\?' == '?\\\?'  # this is the same string... see below
True

Для ваших конкретных примеров в первом случае '?\\\?'первый \экранирует вторую обратную косую черту, оставляя одну обратную косую черту, но третья обратная косая черта остается обратной косой чертой, поскольку \?не является допустимой escape-последовательностью. Следовательно, в результате получается строка ?\\?.

Во втором случае '?\\\\?'первая обратная косая черта экранирует второй, а третья обратная косая черта экранирует четвертую, что приводит к строке ?\\?.

Вот почему три обратной косой черты - это то же самое, что четыре:

>>> '?\\\?' == '?\\\\?'
True

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

>>> '?\\\\\\?'
'?\\\\\\?'
>>> print('?\\\\\\?')
?\\\?

или вы можете найти "сырые" строки более понятными:

>>> r'?\\\?'
'?\\\\\\?'
>>> print(r'?\\\?')
?\\\?

Это включает обработку управляющей последовательности для строкового литерала. Подробнее см. Строковые литералы .

Mhawke
источник
Ты прав '?\\\?'=='?\\?'дает False, я ошибся. Это должно быть так, '?\\\?'=='?\\\\?'как указывает вопрос, я это исправил.
kozooh 01
13

Поскольку \xв строке символов, когда xне один из специальных backslashable персонажей , как n, r, t, 0и т.д., вычисляется в строке с помощью обратной косой черты и затем x.

>>> '\?'
'\\?'
Пол
источник
7

Со страницы лексического анализа Python под строковыми литералами по адресу: https://docs.python.org/2/reference/lexical_analysis.html

Есть таблица, в которой перечислены все распознанные escape-последовательности.

\\ - это escape-последовательность === \

\? не является escape-последовательностью и является === \?

так что '\\\\' - это '\\', за которым следует '\\', который равен '\\' (два экранированных \)

а '\\\' - это '\\', за которым следует '\', который также является '\\' (один экранированный \ и один необработанный \)

также следует отметить, что в отличие от некоторых других языков python не различает одинарные и двойные кавычки, окружающие строковый литерал.

Итак, «String» и «String» - это одно и то же в Python, они не влияют на интерпретацию управляющих последовательностей.

rkh
источник
1

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

Я полагаю, что нужно добавить, что обработка экранирования перемещается слева направо, так что \nсначала находит обратную косую черту, а затем ищет символ, который нужно экранировать, затем находит nи экранирует его; \\nнаходит первую обратную косую черту, находит вторую и экранирует ее, затем находит nи видит в ней буквальное n; \?находит обратную косую черту и ищет символ для экранирования, находит, ?что не может быть экранировано, и поэтому рассматривает \как буквальную обратную косую черту.

Как заметил Махоук, ключевым моментом здесь является то, что интерактивный интерпретатор избегает обратной косой черты при отображении строки. Я предполагаю, что причина этого в том, чтобы гарантировать, что текстовые строки, скопированные из интерпретатора в редактор кода, являются действительными строками Python. Однако в данном случае учет удобства вызывает недоумение.

>>> print('\?') # \? is not a valid escape code so backslash is left as-is
\?
>>> print('\\?') # \\ is a valid escape code, resulting in a single backslash
'\?'

>>> '\?' # same as first example except that interactive interpreter escapes the backslash
\\?
>>> '\\?' # same as second example, backslash is again escaped
\\?
Дождливый
источник