Чому вихідні рядкові літералі Python не можуть закінчуватися одним зворотним косою рисою?


179

Технічно будь-яка непарна кількість нахилів, як описано в документації .

>>> r'\'
  File "<stdin>", line 1
    r'\'
       ^
SyntaxError: EOL while scanning string literal
>>> r'\\'
'\\\\'
>>> r'\\\'
  File "<stdin>", line 1
    r'\\\'
         ^
SyntaxError: EOL while scanning string literal

Схоже, аналізатор може просто ставити зворотні риски в необроблених рядках до звичайних символів (чи не те, про що йдеться про сирі рядки?), Але я, мабуть, пропускаю щось очевидне.


8
схоже, це зараз фейк . можливо, не було б, коли ви задали питання. Я знаю, що цитовані вами документи говорять майже про те саме, але я просто думав, що додам ще одне джерело документації.
oob

Відповіді:


124

Причина пояснюється в частині того розділу, яку я виділив жирним шрифтом:

Рядок лапок можна уникнути за допомогою зворотної косої риси, але косої риски залишаються в рядку; наприклад, r"\""є дійсним рядковим літералом, що складається з двох символів: зворотній косої риси та подвійної лапки; r"\"не є дійсним літеральним рядком (навіть необроблений рядок не може закінчуватися непарною кількістю зворотних косих рядків). Зокрема, необроблена рядок не може закінчуватися однією косою косою рисою (оскільки зворотна косою рисою буде уникнути наступного символу цитати). Зауважимо також, що один похилий ривок, що супроводжується новим рядком, інтерпретується як ці два символи як частина рядка, а не як продовження рядка.

Таким чином, сирі рядки не є на 100% сирими, є ще якась рудиментарна обробка зворотної косої риски.


21
Ох вау ... це дивно. Гарний улов. Має сенс, що r '\' '== "\\'", але все ще дивно, що символ втечі має ефект, не зникаючи.
cdleary

2
@ihightower це може працювати для шляхів до файлової системи, але є й інші напрямки зворотної косої риси. А для шляхів файлової системи не жорстко кодуйте роздільник. Використовуйте 'os.path.sep', а краще функції вищого рівня 'os.path'. (Або "pathlib", якщо є можливість)
oefe

5
Примітка: вирішення полягає у використанні суміжного буквального змісту. r"foo\bar\baz" "\\"(загортання в парень, якщо неоднозначне) створить єдиний буквальний на час компіляції, перша частина якого є необробленою, і лише останній крихітний біт є неочищеним, щоб дозволити зворотний кут нахилу.
ShadowRanger

2
IMO це просто перетворює питання (що дозволено / буде працювати, а що ні), не кажучи, чому це створено таким чином. Існує запис із поширеними запитаннями, який пояснює, чому (необроблені рядки були розроблені для певної мети, і це має сенс у контексті цієї мети).
ShreevatsaR

3
У чому сенс сирих рядків? Схоже, тіньова реалізація концепції.
Меттью Джеймса Бріггса

101

Помилкове уявлення про сирі рядки python полягає в тому, що більшість людей вважають, що зворотна косою рисою (в сирому рядку) є лише регулярним символом, як і всі інші. Це не. Ключовим для розуміння є послідовність підручників цього пітона:

Якщо присутній префікс ' r ' або ' R ', символ, що слідує за косою косою рисою, включається в рядок без змін, і всі косої косої риски залишаються в рядку

Отже, будь-який символ, що йде за косою рисою, є частиною необробленого рядка. Після того, як парсер вводить необроблений рядок (не Unicode) і наштовхується на зворотну косу рису, він знає, що є два символи (зворотна косою рискою та знаком, що слідує за ним).

Сюди:

r'abc \ d ' включає a, b, c, \, d

r'abc \ 'd' містить a, b, c, \, ', d

r'abc \ '' містить a, b, c, \, '

і:

r'abc \ ' містить a, b, c, \,', але зараз немає кінцевої цитати.

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


8
Це насправді зрозуміліше прийнятої відповіді. Приємна поломка.
Божевільний фізик,

4
Я також вважаю це значно зрозумілішим, ніж прийнята відповідь, і я також буваю фізиком
xdavidliu

22

Це так воно і є! Я розглядаю це як один із тих невеликих дефектів пітона!

Я не думаю, що для цього є вагома причина, але це, безумовно, не розбір; дуже легко розібрати сирі рядки з \ як останній символ.

Ловка полягає в тому, що якщо ви дозволите \ бути останнім символом в необробленій рядку, ви не зможете помістити "всередину необробленої рядки. Здається, python пішов з дозволом", а не дозволити \ як останній символ.

Однак це не повинно викликати проблем.

Якщо ви турбуєтеся про те, що не зможете легко записати виправлення папок Windows, як-от c:\mypath\тоді, не переживайте, адже ви можете представити їх як r"C:\mypath", і, якщо вам потрібно додати ім'я підкаталогу, не робіть цього за допомогою з'єднання рядків, для це все-таки не правильний спосіб зробити це! використанняos.path.join

>>> import os
>>> os.path.join(r"C:\mypath", "subfolder")
'C:\\mypath\\subfolder'

2
Хороший допоміжний матеріал. :-) Захисник диявола, хоча: іноді ви хочете розмежувати шляхи до файлів від шляхів до каталогу, додавши роздільник шляху. Приємна річ os.path.join в тому, що він розвалить їх: assert os.path.join ('/ home / cdleary /', 'foo /', 'bar /') == '/ home / cdleary / foo / бар / '
cdleary

Це не має (технічної) різниці! os.path.isdir скаже вам, чи певний шлях - це каталог (папка)
hasen

2
Так, просто вказати комусь, хто читає код, чи очікуєте ви шлях до каталогу чи файлу.
cdleary

Конвенція щодо Windows полягає в тому, що файли завжди мають розширення. зовсім не ймовірно (за звичайних обставин) мати текстовий файл із таким шляхом, як c: \ path \ data
hasen

5
.. або ви можете представити їх як "c: / mypath" і взагалі забути про свої негативні риси :-)
Джон Фухі

14

Для того, щоб ви закінчили необмежену рядок з косою рисою, пропоную скористатися цим трюком:

>>> print r"c:\test"'\\'
test\

14

Ще одна хитрість - використовувати chr (92), оскільки він оцінює значення "\".

Нещодавно мені довелося очистити рядок від нахилів і наступне зробило трюк:

CleanString = DirtyString.replace(chr(92),'')

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


Але що робити, якщо оригінальний рядок містить зворотні риски?
Джозеф Редферн

2
chr (92) жахливо незрозумілий, напевно, краще використовувати "\\"(необроблений рядок із зворотною косою рисою)
clemep

9

Оскільки \ "дозволено всередині необробленого рядка. Тоді його не можна використовувати для ідентифікації кінця літерального рядка.

Чому б не зупинити розбір рядкового літералу, коли ви стикаєтесь з першим "?

Якщо це було так, то \ "не буде дозволено всередині рядкового літералу. Але це так.


1
Саме так. Дизайнери Python, ймовірно, оцінювали життєздатність двох альтернативних варіантів: послідовності з двома символами в \"будь-якій точці подвійного котирування необробленого рядка, АБО \ в кінці подвійного котирування необробленого рядка. Статистика використання повинна надавати перевагу послідовності двох символів де завгодно проти послідовності з одним символом у кінці.
варильні панелі

3

Причина r'\'синтаксичної неправильності полягає в тому, що, хоч рядовий вираз є вихідним, використані лапки (одинарні чи подвійні) завжди повинні бути уникнутими, оскільки вони інакше позначали б кінець цитати. Тож якщо ви хочете висловити одну цитату в межах одного цитованого рядка, іншого способу, ніж використання, немає\' . Те саме стосується і подвійних цитат.

Але ви можете використовувати:

'\\'

4
Не відповідає "чому" :-)
cdleary

2

Інший користувач, який з тих пір видалив свою відповідь (не впевнений, чи хотіли б її зараховувати), припустив, що дизайнери мови Python можуть спростити дизайн аналізатора, використовуючи ті самі правила розбору та розширивши втечу символів до необробленої форми, як заздалегідь (якщо буквальне було позначене як сире).

Я подумав, що це цікава ідея, і я включаю її як вікі спільноти для нащадків.


Але це може вам дозволити уникнути наявності двох окремих кодових рядків кодового синтаксичного аналізу.
cdleary

2

Незважаючи на свою роль, навіть необроблений рядок не може закінчитися одним зворотним косою рисою, тому що косою косою рисою є наступний символ цитати - ви все одно повинні уникати навколишнього символу цитати, щоб вставити його в рядок. Тобто, r "... \" не є дійсним літеральним рядком - необроблена рядок не може закінчуватися непарною кількістю зворотних косих рядків.
Якщо вам потрібно закінчити необмежену рядок одним зворотним косою рисою, ви можете використовувати два, а другий відрізати.


1

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

Це насправді забороняє \ як останній символ, оскільки він уникне "і зробить парсер задушеним". Але, як зазначалося раніше \ є законним.


1
Так - суть проблеми полягала в тому, що сирі рядки трактують \ як буквальний, а не початок послідовності евакуації. Дивна річ у тому, що вона все ще має властивості втечі для цитування, незважаючи на те, що вона трактується як буквальний символ.
cdleary

1

кілька порад:

1) якщо вам потрібно маніпулювати зворотною косою рисою шляху, то стандартним модулем python os.path є ваш друг. наприклад :

os.path.normpath ('c: / folder1 /')

2) якщо ви хочете створити рядки зі зворотною косою рисою, АЛЕ без зворотної косої риски в кінці рядка, то сировинна рядок - ваш друг (використовуйте префікс 'r' перед вашою буквальною рядком). наприклад :

r'\one \two \three'

3) якщо вам потрібно встановити рядок у змінній X із зворотною косою рисою, ви можете зробити це:

X='dummy'
bs=r'\ ' # don't forget the space after backslash or you will get EOL error
X2=bs[0]+X  # X2 now contains \dummy

4) якщо вам потрібно створити рядок із зворотною косою рисою в кінці, тоді поєднайте підказки 2 і 3:

voice_name='upper'
lilypond_display=r'\DisplayLilyMusic \ ' # don't forget the space at the end
lilypond_statement=lilypond_display[:-1]+voice_name

тепер lilypond_statement містить "\DisplayLilyMusic \upper"

хай живе питон! :)

n3on


1
Жоден із них не відповідає на питання "чому", але №3 та №4 не слід використовувати. Нарізання та додавання рядків - це, як правило, погана практика, і вам слід віддати перевагу r '\ dummy' для №3 (що прекрасно працює) та '' .join ([r '\ DisplayLilyMusic', r '\ верх']) до # 4.
cdleary

1
Причина полягає в тому, що рядки незмінні і кожен зріз / конкатенація створює новий незмінний рядковий об'єкт, який зазвичай відкидається. Краще зібрати їх усіх і з'єднати їх разом за один крок зі str.join (компоненти)
cdleary

Ой, ой, не зрозуміло, що ви мали на увазі під №3. Я думаю, що простий '\\' + X вважає за краще створювати рядок просто для того, щоб нарізати його.
cdleary

Щойно знайдіть os.path.normpath, вилучите зворотну косу риску ... Тоді як я повинен накреслити ім'я файлу в шлях ...
Jing He

0

Я зіткнувся з цією проблемою і знайшов часткове рішення, яке добре для деяких випадків. Незважаючи на те, що python не в змозі закінчити рядок одним зворотним косою рисою, він може бути серіалізований і збережений у текстовому файлі з однією косою рисою в кінці. Тому, якщо вам потрібно зберегти текст з однією косою рисою на вашому комп'ютері, можливо:

x = 'a string\\' 
x
'a string\\' 

# Now save it in a text file and it will appear with a single backslash:

with open("my_file.txt", 'w') as h:
    h.write(x)

BTW не працює з json, якщо ви скидаєте його за допомогою бібліотеки json python.

Нарешті, я працюю з Spyder, і я помітив, що якщо я відкрию змінну в текстовому редакторі павука, двічі клацнувши на його ім'я в провіднику змінної, вона буде представлена ​​одним зворотним косою рисою і може бути скопійована в буфер обміну таким чином (це не дуже корисно для більшості потреб, але, можливо, для деяких ..).

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