Чому 3 зворотні скісні риски дорівнюють 4 у рядку Python?


90

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

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

8
Останній нічого не уникає, тому в кінцевому підсумку сам врятувався
Падраїк Каннінгем,

1
Не потрібно включати list()навіть:>>> '?\\\?' '?\\\\?'
daboross

@PadraicCunningham Це не "в кінцевому підсумку вдалося врятувати себе". Що це взагалі означає?
user253751

Забавно, але причина в тому, що вони обидва дорівнюють двом зворотним
косим рискам

@immibis, це саме те, що відбувається. Чи знаєте ви різницю між repr та str? Спробуйте надрукувати обидва слэші в рядку, і це може стати зрозумілим
Падраїк Каннінгем

Відповіді:


84

В основному тому, що python дещо поблажливий при обробці зворотних рисок. Посилання з https://docs.python.org/2.0/ref/strings.html :

На відміну від стандарту С, усі нерозпізнані послідовності екрану залишаються в рядку без змін, тобто зворотна коса риса залишається в рядку .

(Упор в оригіналі)

Отже, у python не те, що три зворотні скісні риски дорівнюють чотирьом, це те, що коли ви слідуєте зворотній косою рисою з таким символом, як ?два, вони разом проходять як два символи, оскільки \?це не розпізнана послідовність виходу.


6
Це протилежність поблажливості. Поблажлива - це поведінка більшості всіх , "якщо ти робиш зворотну косу риску символу, якому це не потрібно, зворотна коса риса нічого не робить". Разом з іншою домовленістю (що зворотна лінія букв і цифр може зробити їх особливими, але зворотна коса рисованість завжди робить їх неспеціальними), ви отримуєте дуже приємну властивість, що ви можете безпечно дефангувати рядок зворотною косою рискою, не знаючи, які символи спеціально interpeted - властивість, якої не вистачає Python.
hobbs

24
Ні, протилежним до поблажливого було б спричинити помилку, коли ви використовуєте невпізнану зворотну скісну риску. (Як і майже кожна скомпільована мова. Пам’ятайте, що обробка рядків Python в основному "подібна C, за винятком того, що ми не продуваємо, коли передаємо недійсні зворотні скісні риски"). - все, що ви використовуєте як роздільник, і саму косу риску. Я не розумію аргументу, що важко запам’ятати їх обох.
Даніель Мартін

@DanielMartin є деякі мови, де роздільник функціонує як власний символ виходу (наприклад 'escape''d'). Вам навіть не потрібно згадувати там інших персонажів!
SztupY

1
О, почекайте, я гадаю, стандартний паскаль теж використовував цю систему - див. Nyx.net/~gthompso/self_pasc.txt
Даніель Мартін

1
@DanielMartin SQL теж.
Random832 02

30

Це пояснюється тим, що зворотна коса риса виконує роль символу втечі для символів, що безпосередньо слідують за нею, якщо комбінація представляє дійсну послідовність екрану. Десяток послідовностей втечі перелічено тут . Вони включають такі очевидні, як новий рядок \n, горизонтальна вкладка \t, повернення каретки \rта більш незрозумілі, такі як використання іменованих символів Unicode \N{...}, наприклад, \N{WAVY DASH}що представляє символ Unicode\u3030 . Однак ключовим моментом є те, що якщо послідовність екрану невідома, послідовність символів залишається в рядку як є.

Частиною проблеми може бути також те, що вихід інтерпретатора 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

Для ваших конкретних прикладів, у першому випадку '?\\\?'перший \виходить з другого зворотного слеша, залишаючи єдиний зворотний слеш, але третій зворотний слеш залишається як зворотний слеш, оскільки \?не є допустимою послідовністю екранування. Отже, отриманий рядок є ?\\?.

У другому випадку '?\\\\?'перша зворотна скісна риска витікає з другої, а третя зворотна коса риса - четвертої, що призводить до появи рядка ?\\?.

Ось чому три зворотні скісні риски - це те саме, що чотири:

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

Якщо ви хочете створити рядок із 3 зворотними скісними рисками, ви можете уникнути кожної зворотної скісної риски:

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

або ви можете знайти "сирі" рядки більш зрозумілими:

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

Це призводить до обробки вхідної послідовності для рядкового літералу. Докладніше див. У розділі String Literals .


Ти маєш рацію '?\\\?'=='?\\?'дає False, я неправильно набраний його. Це має бути, '?\\\?'=='?\\\\?'як вказує питання, я це виправив.
kozooh

13

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

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

7

Зі сторінки лексичного аналізу python під рядковими літералами за адресою: https://docs.python.org/2/reference/lexical_analysis.html

Існує таблиця, в якій перелічені всі розпізнані послідовності екранування.

\\ - це послідовність екрану, яка === \

\? не є послідовністю виходу та є === \?

отже, "\\\\" - це "\\", за яким слідує "\\", тобто "\\" (два втекли \)

і '\\\' - це '\\', за яким слідує '\', який також є '\\' (один вийшов \ і один сирий \)

також слід зазначити, що python не розрізняє одинарні та подвійні лапки навколо рядкового літералу, на відміну від деяких інших мов.

Отже, "Рядок" і "Рядок" - це те саме, що в python, вони не впливають на інтерпретацію послідовностей екранування.


1

Відповідь mhawke майже охоплює це, я просто хочу перекласти його у більш стислій формі та з мінімальними прикладами, що ілюструють таку поведінку.

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

Як зазначив 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
\\?
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.