Tại sao 3 dấu gạch chéo ngược bằng 4 trong một chuỗi Python?


90

Bạn có thể cho tôi biết tại sao '?\\\?'=='?\\\\?'lại cho True? Điều đó khiến tôi phát điên và tôi không thể tìm ra câu trả lời hợp lý ...

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

8
Sau đó không thoát bất cứ điều gì để nó kết thúc lên được thoát thân
Padraic Cunningham

1
Không cần bao gồm số list()chẵn:>>> '?\\\?' '?\\\\?'
daboross

@PadraicCunningham Nó không "tự thoát ra". Điều đó thậm chí có nghĩa là gì?
user253751

Amusingly, lý do là họ đang cả bằng hai dấu xồ nguợc :-)
RemcoGerlich

@immibis, đó chính xác là những gì đang xảy ra. Bạn có biết sự khác biệt giữa repr và str không? Thử in cả với một dấu chéo ngược trong chuỗi và nó có thể trở nên rõ ràng
Padraic Cunningham

Câu trả lời:


84

Về cơ bản, vì python hơi khoan dung trong việc xử lý dấu gạch chéo ngược. Trích dẫn từ https://docs.python.org/2.0/ref/strings.html :

Không giống như Tiêu chuẩn C, tất cả các chuỗi thoát không được nhận dạng đều được giữ nguyên trong chuỗi, tức là, dấu gạch chéo ngược được để lại trong chuỗi .

(Nhấn mạnh trong bản gốc)

Do đó, trong python, không phải là ba dấu gạch chéo ngược bằng bốn, mà là khi bạn theo sau dấu gạch chéo ngược với một ký tự như ?, cả hai kết hợp với nhau dưới dạng hai ký tự, vì \?không phải là một chuỗi thoát được công nhận.


6
Đó là điều đối lập với nhân hậu. Lenient là hành vi của hầu hết mọi người khác về "nếu bạn gạch chéo ngược một ký tự không cần nó, dấu gạch chéo ngược không làm gì cả". Cùng với một quy ước khác (chữ và số gạch chéo ngược có thể làm cho chúng trở nên đặc biệt, nhưng dấu câu gạch chéo ngược luôn làm cho nó không đặc biệt), bạn sẽ có được một thuộc tính rất hay mà bạn có thể gỡ rối một chuỗi một cách an toàn bằng cách gạch ngược tất cả các dấu câu mà không cần biết ký tự nào là đặc biệt interpised - một thuộc tính mà Python thiếu.
hobbs

24
Không, ngược lại với khoan dung sẽ gây ra lỗi khi bạn sử dụng lối thoát dấu gạch chéo ngược không được công nhận. (Như hầu hết mọi ngôn ngữ biên dịch đều vậy. Hãy nhớ rằng xử lý chuỗi của Python về cơ bản là "giống như C, ngoại trừ việc chúng ta không bị nổ khi thoát dấu gạch chéo ngược không hợp lệ được đưa ra") Ngoài ra, trong một chuỗi bất kể ngôn ngữ nào, chỉ có hai ký tự cần thoát - bất kỳ thứ gì bạn đang sử dụng làm dấu phân cách và dấu gạch chéo ngược của chính nó. Tôi không hiểu lập luận rằng rất khó để nhớ cả hai.
Daniel Martin

@DanielMartin có một số ngôn ngữ mà dấu phân cách hoạt động như ký tự thoát của chính nó (ví dụ 'escape''d':). Bạn thậm chí không cần phải nhớ các ký tự khác ở đó!
SztupY

1
Ồ, chờ đã, tôi đoán pascal tiêu chuẩn cũng đã sử dụng hệ thống đó - xem nyx.net/~gthompso/self_pasc.txt
Daniel Martin

1
@DanielMartin SQL nữa.
Ngẫu nhiên832

30

Điều này là do dấu gạch chéo ngược hoạt động như một ký tự thoát cho (các) ký tự ngay sau nó, nếu sự kết hợp đại diện cho một chuỗi thoát hợp lệ. Hàng tá trình tự thoát được liệt kê ở đây . Chúng bao gồm những cái rõ ràng như xuống dòng \n, tab ngang \t, vận chuyển trở lại \rvà những người mơ hồ hơn như các ký tự unicode tên sử dụng \N{...}, ví dụ như \N{WAVY DASH}đại diện cho ký tự unicode\u3030 . Tuy nhiên, điểm mấu chốt là nếu trình tự thoát không được biết thì chuỗi ký tự vẫn được giữ nguyên trong chuỗi.

Một phần của vấn đề cũng có thể là do đầu ra của trình thông dịch Python gây hiểu lầm cho bạn. Điều này là do dấu gạch chéo ngược được thoát ra khi hiển thị. Tuy nhiên, nếu bạn in các chuỗi đó, bạn sẽ thấy các dấu gạch chéo ngược thừa biến mất.

>>> '?\\\?'
'?\\\\?'
>>> 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

Đối với các ví dụ cụ thể của bạn, trong trường hợp đầu tiên '?\\\?', đầu tiên \thoát khỏi dấu gạch chéo ngược thứ hai để lại một dấu gạch chéo ngược duy nhất, nhưng dấu gạch chéo ngược thứ ba vẫn là dấu gạch chéo ngược vì \?không phải là chuỗi thoát hợp lệ. Do đó, chuỗi kết quả là ?\\?.

Đối với trường hợp thứ hai '?\\\\?', dấu gạch chéo ngược đầu tiên thoát khỏi dấu gạch chéo ngược thứ hai và dấu gạch chéo ngược thứ ba thoát khỏi dấu gạch chéo ngược thứ tư dẫn đến chuỗi ?\\?.

Vì vậy, đó là lý do tại sao ba dấu gạch chéo ngược giống như bốn:

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

Nếu bạn muốn tạo một chuỗi có 3 dấu gạch chéo ngược, bạn có thể thoát từng dấu gạch chéo ngược:

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

hoặc bạn có thể thấy chuỗi "thô" dễ hiểu hơn:

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

Đây là lượt xử lý trình tự thoát cho chuỗi ký tự. Xem String Literals để biết thêm chi tiết.


Bạn '?\\\?'=='?\\?'cho đúng False, tôi đã gõ sai. Đó phải là '?\\\?'=='?\\\\?'như câu hỏi chỉ ra, tôi đã sửa nó.
kozooh

13

Bởi vì \xtrong một chuỗi ký tự, khi xkhông phải là một trong những nhân vật đặc biệt như backslashable n, r, t, 0, vv, đánh giá lại thành một chuỗi với một dấu chéo ngược và sau đó một x.

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

7

Từ trang phân tích từ vựng python trong chuỗi ký tự tại: https://docs.python.org/2/reference/lexical_analysis.html

Có một bảng liệt kê tất cả các chuỗi thoát được công nhận.

\\ là một chuỗi thoát === \

\? không phải là một chuỗi thoát và là === \?

vì vậy '\\\\' là '\\' theo sau là '\\' là '\\' (hai thoát \)

và '\\\' là '\\' theo sau là '\' cũng là '\\' (một thoát \ và một nguyên \)

Ngoài ra, cần lưu ý rằng python không phân biệt giữa dấu ngoặc kép đơn và dấu ngoặc kép xung quanh một chuỗi ký tự, không giống như một số ngôn ngữ khác.

Vì vậy, 'String' và "String" hoàn toàn giống nhau trong python, chúng không ảnh hưởng đến việc giải thích các chuỗi thoát.


1

Câu trả lời của mhawke bao hàm khá nhiều vấn đề, tôi chỉ muốn trình bày lại nó dưới dạng ngắn gọn hơn và với các ví dụ tối thiểu minh họa hành vi này.

Tôi đoán một điều cần thêm là xử lý thoát di chuyển từ trái sang phải, vì vậy \nđầu tiên tìm dấu gạch chéo ngược và sau đó tìm kiếm một nhân vật để thoát, sau đó tìm nvà thoát khỏi nó; \\ntìm dấu gạch chéo ngược đầu tiên, tìm thứ hai và thoát khỏi nó, sau đó tìm nvà coi nó như một chữ n; \?tìm dấu gạch chéo ngược và tìm một ký tự để thoát, tìm ký tự ?không thể thoát và vì vậy được coi \như một dấu gạch chéo ngược theo nghĩa đen.

Như mhawke đã lưu ý, chìa khóa ở đây là trình thông dịch tương tác thoát khỏi dấu gạch chéo ngược khi hiển thị một chuỗi. Tôi đoán lý do cho điều đó là để đảm bảo rằng các chuỗi văn bản được sao chép từ trình thông dịch vào trình soạn thảo mã là các chuỗi python hợp lệ. Tuy nhiên, trong trường hợp khoản trợ cấp này để thuận tiện gây ra sự nhầm lẫn.

>>> 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
\\?
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.