Tại sao chuỗi ký tự thô của Python không thể kết thúc bằng một dấu gạch chéo ngược?


178

Về mặt kỹ thuật, bất kỳ số lượng dấu gạch chéo lẻ, như được mô tả trong tài liệu .

>>> 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

Có vẻ như trình phân tích cú pháp chỉ có thể coi dấu gạch chéo ngược trong các chuỗi thô như các ký tự thông thường (không phải đó là tất cả các chuỗi thô là gì?), Nhưng tôi có thể thiếu một cái gì đó rõ ràng.


8
Có vẻ như đây là một faq . có thể không có được khi bạn đặt câu hỏi. Tôi biết các tài liệu bạn trích dẫn nói khá nhiều điều tương tự, nhưng tôi chỉ nghĩ rằng tôi sẽ thêm một nguồn tài liệu khác.
oob

Câu trả lời:


124

Lý do được giải thích trong phần của phần mà tôi nhấn mạnh bằng chữ in đậm:

Dấu ngoặc kép có thể được thoát bằng dấu gạch chéo ngược, nhưng dấu gạch chéo ngược vẫn nằm trong chuỗi; ví dụ, r"\""là một chuỗi ký tự hợp lệ bao gồm hai ký tự: dấu gạch chéo ngược và dấu ngoặc kép; r"\"không phải là một chuỗi ký tự hợp lệ (ngay cả một chuỗi thô cũng không thể kết thúc bằng một số dấu gạch chéo ngược lẻ). Cụ thể, một chuỗi thô không thể kết thúc bằng một dấu gạch chéo ngược (vì dấu gạch chéo ngược sẽ thoát khỏi ký tự trích dẫn sau). Cũng lưu ý rằng một dấu gạch chéo ngược đơn theo sau một dòng mới được hiểu là hai ký tự đó là một phần của chuỗi, không phải là một dòng tiếp tục.

Vì vậy, chuỗi thô không phải là 100% thô, vẫn còn một số xử lý dấu gạch chéo thô sơ.


20
Ôi chà ... thật lạ. Bắt đẹp. Có nghĩa là r '\' '== "\\'" nhưng vẫn lạ là nhân vật thoát có hiệu ứng mà không biến mất.
cdleary 15/03/2016

2
@ihightower điều này có thể hoạt động cho các đường dẫn hệ thống tệp, nhưng có những cách sử dụng dấu gạch chéo ngược khác. Và đối với đường dẫn hệ thống tệp, không mã hóa dấu phân cách. Sử dụng 'os.path.sep' hoặc tốt hơn là các tính năng cấp cao hơn của 'os.path'. (Hoặc 'pathlib', khi khả dụng)
oefe

5
Lưu ý: Cách giải quyết là sử dụng phép nối nghĩa đen liền kề. r"foo\bar\baz" "\\"(bọc trong parens nếu mơ hồ) sẽ tạo ra một chữ duy nhất tại thời gian biên dịch, phần đầu tiên là thô và chỉ một bit nhỏ cuối cùng là không thô, để cho phép dấu gạch chéo ngược.
ShadowRanger

2
IMO điều này chỉ đặt lại câu hỏi (những gì được phép / sẽ hoạt động và những gì không), mà không nói lý do tại sao nó được thiết kế theo cách này. Có một mục Câu hỏi thường gặp giải thích lý do tại sao (chuỗi thô được thiết kế cho một mục đích cụ thể và nó có ý nghĩa trong bối cảnh của mục đích đó).
ShreevatsaR

3
Điểm của chuỗi thô là gì? Có vẻ như một thực hiện mờ ám của khái niệm.
Matthew James Briggs

100

Toàn bộ quan niệm sai lầm về chuỗi thô của python là hầu hết mọi người nghĩ rằng dấu gạch chéo ngược (trong chuỗi thô) chỉ là một ký tự thông thường như tất cả những người khác. Không phải vậy. Chìa khóa để hiểu là trình tự hướng dẫn của con trăn này:

Khi có tiền tố ' r ' hoặc ' R ', một ký tự theo dấu gạch chéo ngược được bao gồm trong chuỗi mà không thay đổi và tất cả dấu gạch chéo ngược được để lại trong chuỗi

Vì vậy, bất kỳ ký tự nào sau dấu gạch chéo ngược một phần của chuỗi thô. Khi trình phân tích cú pháp nhập vào một chuỗi thô (không phải là Unicode) và gặp dấu gạch chéo ngược, nó biết có 2 ký tự (dấu gạch chéo ngược và ký tự theo sau nó).

Cách này:

r'abc \ d ' bao gồm a, b, c, \, d

r'abc \ 'd' bao gồm a, b, c, \, ', d

r'abc \ '' bao gồm a, b, c, \, '

và:

r'abc \ ' bao gồm a, b, c, \,' nhưng hiện tại không có trích dẫn chấm dứt.

Trường hợp cuối cùng cho thấy rằng theo tài liệu bây giờ, trình phân tích cú pháp không thể tìm thấy trích dẫn đóng vì trích dẫn cuối cùng bạn thấy ở trên là một phần của chuỗi, nghĩa là dấu gạch chéo ngược không thể tồn tại ở đây vì nó sẽ 'nuốt chửng' chuỗi đóng char.


8
Điều này thực sự rõ ràng hơn câu trả lời được chấp nhận. Sự cố tốt đẹp.
Nhà vật lý điên

4
tôi cũng thấy điều này rõ ràng hơn câu trả lời được chấp nhận và tôi cũng là một nhà vật lý
xdavidliu

22

No chinh la như thê! Tôi thấy đó là một trong những khuyết điểm nhỏ ở trăn!

Tôi không nghĩ rằng có một lý do tốt cho nó, nhưng nó chắc chắn không phân tích cú pháp; thật dễ dàng để phân tích các chuỗi thô với \ là ký tự cuối cùng.

Điều hấp dẫn là, nếu bạn cho phép \ là ký tự cuối cùng trong một chuỗi thô thì bạn sẽ không thể đặt "bên trong một chuỗi thô. Có vẻ như python đã cho phép" thay vì cho phép \ là ký tự cuối cùng.

Tuy nhiên, điều này không gây ra bất kỳ rắc rối.

Nếu bạn lo lắng về việc không thể dễ dàng viết các đường dẫn thư mục windows như vậy c:\mypath\thì đừng lo lắng, vì, bạn có thể đại diện cho chúng như r"C:\mypath", và, nếu bạn cần thêm một tên thư mục con, đừng làm điều đó với nối chuỗi Dù sao đó cũng không phải là cách đúng đắn! sử dụngos.path.join

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

2
Vật liệu phụ trợ tốt. :-) Người ủng hộ của Devil, mặc dù: đôi khi bạn muốn phân biệt đường dẫn tệp với đường dẫn thư mục bằng cách nối thêm dấu phân cách đường dẫn. Một điều thú vị về os.path.join là nó sẽ đánh sập chúng: khẳng định os.path.join ('/ home / cdleary /', 'foo /', 'bar /') == '/ home / cdleary / foo / thanh / '
cdleary

Nó không làm cho một sự khác biệt (kỹ thuật) mặc dù! os.path.isdir sẽ cho bạn biết một con đường nhất định là một thư mục (folder)
Hasen

2
Đúng, nó chỉ để chỉ cho ai đó đọc mã cho dù bạn mong muốn một đường dẫn là một thư mục hoặc một tệp.
cdleary

Quy ước trên windows là các tệp luôn có phần mở rộng. hoàn toàn không có khả năng (trong các trường hợp thông thường) có tệp văn bản có đường dẫn như c: \ path \ data
hasen

5
.. hoặc bạn có thể đại diện cho họ là "c: / mypath" và quên đi những dấu gạch chéo ngược của bạn hoàn toàn :-)
John Fouhy

14

Để bạn kết thúc một chuỗi thô bằng dấu gạch chéo, tôi khuyên bạn nên sử dụng thủ thuật này:

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

14

Một mẹo khác là sử dụng chr (92) vì nó ước tính là "\".

Gần đây tôi đã phải xóa một chuỗi dấu gạch chéo ngược và sau đây đã thực hiện thủ thuật:

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

Tôi nhận ra rằng điều này không quan tâm đến "tại sao" nhưng chủ đề thu hút nhiều người tìm kiếm giải pháp cho một vấn đề tức thời.


Nhưng nếu chuỗi gốc chứa dấu gạch chéo ngược thì sao?
Joseph Redfern

2
chr (92) rất tối nghĩa, có lẽ tốt hơn để sử dụng "\\"(chuỗi không thô với dấu gạch chéo ngược)
clemep

9

Vì \ "được phép bên trong chuỗi thô. Sau đó, nó không thể được sử dụng để xác định phần cuối của chuỗi ký tự.

Tại sao không ngừng phân tích chuỗi ký tự khi bạn gặp lần đầu tiên "?

Nếu đó là trường hợp, thì \ "sẽ không được phép bên trong chuỗi ký tự. Nhưng nó là.


1
Chính xác. Các nhà thiết kế Python có thể đã đánh giá khả năng của hai lựa chọn thay thế: chuỗi hai ký tự ở \"bất cứ đâu trong chuỗi thô được trích dẫn kép, OR \ ở cuối chuỗi thô được trích dẫn kép. Thống kê sử dụng phải ưu tiên chuỗi hai ký tự ở bất cứ đâu so với chuỗi một ký tự ở cuối.
hobs

3

Lý do tại sao r'\'cú pháp không chính xác là vì mặc dù biểu thức chuỗi là thô, các trích dẫn được sử dụng (đơn hoặc kép) luôn phải thoát vì chúng sẽ đánh dấu kết thúc của trích dẫn. Vì vậy, nếu bạn muốn diễn đạt một trích dẫn bên trong chuỗi trích dẫn đơn, không có cách nào khác ngoài việc sử dụng \'. Áp dụng tương tự cho dấu ngoặc kép.

Nhưng bạn có thể sử dụng:

'\\'

4
Không trả lời 'tại sao' :-)
cdleary

2

Một người dùng khác đã xóa câu trả lời của họ (không chắc họ có muốn được ghi nhận hay không) đề xuất rằng các nhà thiết kế ngôn ngữ Python có thể đơn giản hóa thiết kế trình phân tích cú pháp bằng cách sử dụng cùng một quy tắc phân tích cú pháp và mở rộng các ký tự thoát thành dạng thô như một suy nghĩ sau (nếu nghĩa đen được đánh dấu là thô).

Tôi nghĩ rằng đó là một ý tưởng thú vị và bao gồm nó như là wiki cộng đồng cho hậu thế.


Nhưng nó có thể cho phép bạn tránh có hai đường dẫn mã trình phân tích cú pháp chuỗi riêng biệt.
cdleary 15/03/2016

2

Mặc dù vai trò của nó, ngay cả một chuỗi thô cũng không thể kết thúc bằng một dấu gạch chéo ngược, bởi vì dấu gạch chéo ngược thoát khỏi ký tự trích dẫn sau đây, bạn vẫn phải thoát ký tự trích dẫn xung quanh để nhúng nó vào chuỗi. Đó là, r "... \" không phải là một chuỗi ký tự hợp lệ, một chuỗi thô không thể kết thúc bằng một số dấu gạch chéo ngược.
Nếu bạn cần kết thúc một chuỗi thô bằng một dấu gạch chéo ngược đơn, bạn có thể sử dụng hai và cắt chuỗi thứ hai.


1

Theo tôi, khá rõ ràng rằng một \ hoạt động như một ký tự thoát cho phép bạn đặt các ký tự đặc biệt như dòng mới, tab và dấu ngoặc kép thành chuỗi.

Điều đó thực sự không cho phép \ là ký tự cuối cùng vì nó sẽ thoát khỏi "và làm cho trình phân tích cú pháp bị nghẹt thở. Nhưng như đã chỉ ra trước đó \ là hợp pháp.


1
Vâng - cốt lõi của vấn đề là các chuỗi thô coi \ như một nghĩa đen thay vì bắt đầu một chuỗi thoát. Điều kỳ lạ là nó vẫn có các thuộc tính thoát để trích dẫn, mặc dù được coi là một nhân vật theo nghĩa đen.
cdleary 15/03/2016

1

một số lời khuyên :

1) nếu bạn cần thao tác dấu gạch chéo ngược cho đường dẫn thì mô-đun python chuẩn os.path là bạn của bạn. ví dụ :

os.path.normpath ('c: / thư mục1 /')

2) nếu bạn muốn xây dựng chuỗi có dấu gạch chéo ngược trong đó NHƯNG không có dấu gạch chéo ngược ở END của chuỗi thì chuỗi thô là bạn của bạn (sử dụng tiền tố 'r' trước chuỗi ký tự của bạn). ví dụ :

r'\one \two \three'

3) nếu bạn cần tiền tố một chuỗi trong biến X với dấu gạch chéo ngược thì bạn có thể làm điều này:

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) nếu bạn cần tạo một chuỗi có dấu gạch chéo ngược ở cuối, sau đó kết hợp mẹo 2 và 3:

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

bây giờ lilypond_statement chứa "\DisplayLilyMusic \upper"

trăn sống lâu! :)

n3on


1
Không ai trong số này trả lời câu hỏi "tại sao", nhưng # 3 và # 4 không nên được sử dụng. Cắt và thêm chuỗi nói chung là thực tế xấu và bạn nên ưu tiên r '\ dummy' cho # 3 (hoạt động tốt) và '' .join ([r '\ DisplayLilyMusic', r '\ Upper']) cho # 4.
cdleary

1
Lý do là các chuỗi là bất biến và mỗi lát / ghép tạo ra một đối tượng chuỗi bất biến mới thường bị loại bỏ. Tốt hơn là tích lũy tất cả chúng và tham gia cùng nhau trong một bước với str.join (các thành phần)
cdleary

Ồ, rất tiếc - đã hiểu nhầm ý của bạn về # 3. Tôi nghĩ rằng có một '\' + X đơn giản được ưu tiên để tạo một chuỗi chỉ để cắt nó.
cdleary 15/03/2016

Chỉ cần tìm os.path.normpathsẽ loại bỏ dấu gạch chéo ngược ... Sau đó, làm cách nào để ghép tên tệp vào đường dẫn ...
Jing He

0

Tôi gặp phải vấn đề này và tìm thấy một giải pháp một phần tốt cho một số trường hợp. Mặc dù python không thể kết thúc một chuỗi bằng một dấu gạch chéo ngược, nó có thể được tuần tự hóa và lưu trong một tệp văn bản với một dấu gạch chéo ngược ở cuối. Do đó, nếu những gì bạn cần là lưu một văn bản với một dấu gạch chéo ngược trên máy tính của bạn, thì có thể:

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 nó không hoạt động với json nếu bạn kết xuất nó bằng thư viện json của python.

Cuối cùng, tôi làm việc với Spyder và tôi nhận thấy rằng nếu tôi mở biến trong trình soạn thảo văn bản của nhện bằng cách nhấp đúp vào tên của nó trong trình thám hiểm biến, nó được hiển thị với một dấu gạch chéo ngược và có thể được sao chép vào bảng tạm theo cách đó (không phải vậy rất hữu ích cho hầu hết các nhu cầu nhưng có thể cho một số ..).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.