Mengapa 3 garis miring terbalik sama dengan 4 dalam string Python?

90

Bisakah Anda memberi tahu saya mengapa '?\\\?'=='?\\\\?'memberi True? Itu membuat saya gila dan saya tidak dapat menemukan jawaban yang masuk akal ...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']
kozooh
sumber
8
Yang terakhir ini tidak melarikan diri dari apa pun sehingga akhirnya melarikan diri
Padraic Cunningham
1
list()Bahkan tidak perlu menyertakan :>>> '?\\\?' '?\\\\?'
daboross
@PadraicCunningham Itu tidak "berakhir dengan melarikan diri sendiri". Apa artinya itu?
pengguna253751
Anehnya, alasannya adalah bahwa keduanya sama dengan dua garis miring terbalik :-)
RemcoGerlich
@immibis, itulah yang terjadi. Tahukah Anda perbedaan antara repr dan str? Coba cetak keduanya dengan satu garis miring terbalik di string dan itu mungkin menjadi jelas
Padraic Cunningham

Jawaban:

84

Pada dasarnya, karena python sedikit lunak dalam pemrosesan garis miring terbalik. Mengutip dari https://docs.python.org/2.0/ref/strings.html :

Tidak seperti Standard C, semua escape sequences yang tidak dikenali dibiarkan dalam string tidak berubah, misalnya, garis miring terbalik dibiarkan dalam string .

(Penekanan dalam bahasa aslinya)

Oleh karena itu, dalam python, tiga garis miring terbalik tidak sama dengan empat, tetapi ketika Anda mengikuti garis miring terbalik dengan karakter seperti ?, keduanya bersama-sama muncul sebagai dua karakter, karena \?bukan urutan pelolosan yang dikenali.

Daniel Martin
sumber
6
Itu kebalikan dari lunak. Lenient adalah perilaku kebanyakan orang lain "jika Anda melakukan backslash pada karakter yang tidak membutuhkannya, backslash tidak melakukan apa-apa". Bersama dengan konvensi lain (bahwa huruf miring terbalik dapat membuatnya istimewa, tetapi tanda baca backslashing selalu membuatnya tidak istimewa), Anda mendapatkan properti yang sangat bagus bahwa Anda dapat menghilangkan string dengan aman dengan melakukan backslashing semua tanda baca, tanpa harus mengetahui karakter mana yang secara khusus. interpeted - properti yang tidak dimiliki Python.
Hobbs
24
Tidak, kebalikan dari lenient adalah memunculkan error saat Anda menggunakan escape backslash yang tidak dikenali. (Seperti hampir semua bahasa yang dikompilasi. Ingat bahwa pemrosesan string Python pada dasarnya "seperti C, kecuali bahwa kita tidak meledak ketika diberikan escapes garis miring terbalik yang tidak valid") Selain itu, dalam string apa pun bahasanya, hanya ada dua karakter yang perlu keluar - apa pun yang Anda gunakan sebagai pembatas, dan garis miring terbalik itu sendiri. Saya tidak mengerti argumen bahwa sulit untuk mengingat keduanya.
Daniel Martin
@DanielMartin ada beberapa bahasa di mana pembatas berfungsi sebagai karakter pelariannya sendiri (misalnya 'escape''d'). Anda bahkan tidak perlu mengingat karakter lain di sana!
SztupY
1
Oh tunggu, saya rasa pascal standar juga menggunakan sistem itu - lihat nyx.net/~gthompso/self_pasc.txt
Daniel Martin
1
@Danielin SQL juga.
Random832
30

Ini karena garis miring terbalik bertindak sebagai karakter escape untuk karakter yang segera mengikutinya, jika kombinasi mewakili urutan escape yang valid. Selusin atau lebih urutan pelarian tercantum di sini . Mereka termasuk yang sudah jelas seperti baris baru \n, tab horizontal \t, carriage return \rdan yang lebih tidak jelas seperti karakter unicode yang diberi nama \N{...}, misalnya \N{WAVY DASH}yang mewakili karakter unicode \u3030. Intinya adalah jika urutan escape tidak diketahui, urutan karakter dibiarkan dalam string apa adanya.

Sebagian dari masalahnya mungkin juga karena keluaran interpreter Python menyesatkan Anda. Ini karena garis miring terbalik di-escape saat ditampilkan. Namun, jika Anda mencetak string tersebut, Anda akan melihat garis miring terbalik ekstra menghilang.

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

Untuk contoh spesifik Anda, dalam kasus pertama '?\\\?', yang pertama \mengosongkan garis miring terbalik kedua meninggalkan satu garis miring terbalik, tetapi garis miring terbalik ketiga tetap sebagai garis miring terbalik karena \?bukan urutan escape yang valid. Karenanya string yang dihasilkan adalah ?\\?.

Untuk kasus kedua '?\\\\?', garis miring terbalik pertama lolos dari kedua, dan garis miring terbalik ketiga lolos keempat yang menghasilkan string ?\\?.

Jadi itulah mengapa tiga garis miring terbalik sama dengan empat:

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

Jika Anda ingin membuat string dengan 3 garis miring terbalik, Anda dapat keluar dari setiap garis miring terbalik:

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

atau Anda mungkin menemukan string "mentah" yang lebih mudah dipahami:

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

Ini mengubah pemrosesan urutan escape untuk string literal. Lihat String Literals untuk lebih jelasnya.

mhawke
sumber
Anda benar '?\\\?'=='?\\?'memberi False, saya salah mengetik. Seharusnya '?\\\?'=='?\\\\?'seperti yang ditunjukkan oleh pertanyaan, saya telah memperbaikinya.
kozooh
13

Karena \xdalam string karakter, ketika xtidak salah satu karakter backslashable khusus seperti n, r, t, 0, dll, mengevaluasi ke string dengan garis miring terbalik dan kemudian x.

>>> '\?'
'\\?'
paul
sumber
7

Dari halaman analisis leksikal python di bawah string literals di: https://docs.python.org/2/reference/lexical_analysis.html

Ada tabel yang mencantumkan semua escape sequence yang dikenali.

\\ adalah escape sequence yaitu === \

\? bukan merupakan escape sequence dan merupakan === \?

jadi '\\\\' adalah '\\' diikuti oleh '\\' yang merupakan '\\' (dua lolos \)

dan '\\\' adalah '\\' diikuti oleh '\' yang juga merupakan '\\' (satu lolos \ dan satu mentah \)

Selain itu, perlu dicatat bahwa python tidak membedakan antara tanda kutip tunggal dan ganda yang mengelilingi literal string, tidak seperti beberapa bahasa lain.

Jadi 'String' dan "String" adalah hal yang sama persis di python, mereka tidak mempengaruhi interpretasi dari urutan escape.

rkh
sumber
1

Jawaban mhawke cukup banyak mencakupnya, saya hanya ingin menyatakannya kembali dalam bentuk yang lebih ringkas dan dengan sedikit contoh yang menggambarkan perilaku ini.

Saya kira satu hal yang perlu ditambahkan adalah bahwa proses melarikan diri bergerak dari kiri ke kanan, sehingga \npertama - tama menemukan garis miring terbalik dan kemudian mencari karakter untuk melarikan diri, kemudian menemukan ndan melarikan diri; \\nmenemukan garis miring terbalik pertama, menemukan garis miring kedua dan menghindarinya, kemudian menemukan ndan melihatnya sebagai n literal; \?menemukan garis miring terbalik dan mencari karakter untuk melarikan diri, menemukan ?yang tidak dapat melarikan diri, dan diperlakukan \sebagai garis miring terbalik literal.

Seperti dicatat mhawke, kuncinya di sini adalah bahwa interpreter interaktif lolos dari garis miring terbalik saat menampilkan string. Saya menduga alasannya adalah untuk memastikan bahwa string teks yang disalin dari interpreter ke editor kode adalah string python yang valid. Namun, dalam hal ini pemberian kemudahan ini menyebabkan kebingungan.

>>> 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
\\?
Hujan
sumber