Почему 3 обратных слэша равны 4 в строке Python?

Не могли бы вы сказать мне, почему '?\\\?'=='?\\\\?' дает True? Это сводит меня с ума, и я не могу найти разумный ответ...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']

Ответ 1

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

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

(Акцент в оригинале)

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

Ответ 2

Это связано с тем, что обратная косая черта действует как escape-символ для символа (ов), сразу же после него, если комбинация представляет собой действительную escape-последовательность. Примерно дюжина escape-последовательностей указанная здесь. Они включают в себя такие очевидные, как newline \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'?\\\?')
?\\\?

Это завершает обработку escape-последовательности для строкового литерала. Подробнее см. String Literals.

Ответ 3

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

>>> '\?'
'\\?'

Ответ 4

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

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

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

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

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

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

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

Итак, "String" и "String" - это то же самое в python, они не влияют на интерпретацию escape-последовательностей.

Ответ 5

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

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

Как отмечалось в mhawke, ключ здесь заключается в том, что интерактивный интерпретатор ускоряет обратную косую черту при отображении строки. Я предполагаю, что причина в том, что текстовые строки, скопированные из интерпретатора в редактор кода, являются допустимыми строками 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
\\?