Не могли бы вы сказать мне, почему '?\\\?'=='?\\\\?'
дает True
? Это сводит меня с ума, и я не могу найти разумный ответ...
>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']
Не могли бы вы сказать мне, почему '?\\\?'=='?\\\\?'
дает True
? Это сводит меня с ума, и я не могу найти разумный ответ...
>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']
В принципе, потому что python слегка снисходителен в обработке обратной косой черты. Цитирование из https://docs.python.org/2.0/ref/strings.html:
В отличие от стандарта C, все непризнанные escape-последовательности остаются в строке неизменной, то есть обратная косая черта остается в строке.
(Акцент в оригинале)
Таким образом, в python это не так, что три обратных слэша равны четырем, так что когда вы следуете обратным слэшем с символом типа ?
, эти два вместе проходят через два символа, потому что \?
не является распознанной escape-последовательности.
Это связано с тем, что обратная косая черта действует как 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.
Поскольку \x
в символьной строке, когда x
не является одним из специальных символов с обратным слэшем, например n
, r
, t
, 0
и т.д., оценивает строку с обратной косой чертой а затем a x
.
>>> '\?'
'\\?'
На странице лексического анализа python под строковыми литералами: https://docs.python.org/2/reference/lexical_analysis.html
Существует таблица, в которой перечислены все распознанные escape-последовательности.
\\ - это escape-последовательность, которая ===\
\? не является escape-последовательностью и === \?
поэтому '\\\\' - это '\\', за которым следует '\\', который равен\\'(два экранированных \)
и '\\\' - '\\', за которым следует '\', который также является '\\' (один из экранированных\и один raw \)
также следует отметить, что python не различает одинарные и двойные кавычки, окружающие строковый литерал, в отличие от некоторых других языков.
Итак, "String" и "String" - это то же самое в python, они не влияют на интерпретацию escape-последовательностей.
Ответ 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
\\?