Python dizesinde neden 3 ters eğik çizgi 4'e eşittir?


90

Bana neden '?\\\?'=='?\\\\?'verdiğini söyleyebilir misin True? Bu beni çıldırtıyor ve mantıklı bir cevap bulamıyorum ...

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

8
İkincisi hiçbir şeyden kaçmıyor, bu yüzden kendiliğinden kaçıyor
Padraic Cunningham

1
list()>>> '?\\\?' '?\\\\?'
Eşit eklemeye

@PadraicCunningham "Kendinden kaçmakla bitmiyor". Bu ne anlama geliyor?
user253751

Eğlenceli bir şekilde, nedeni her ikisinin de iki ters eğik
çizgiye

@immibis, tam olarak olan bu. Repr ve str arasındaki farkı biliyor musunuz? Her ikisini de dizede bir ters eğik çizgi ile yazdırmayı deneyin ve
netleşebilir

Yanıtlar:


84

Temel olarak, python ters eğik çizgi işlemede biraz esnek olduğu için. Https://docs.python.org/2.0/ref/strings.html adresinden alıntı :

Standart C'den farklı olarak, tüm tanınmayan kaçış dizileri dizede değiştirilmeden bırakılır, yani ters eğik çizgi dizede bırakılır .

(Orijinal metinde vurgu)

Bu nedenle, python'da, üç ters eğik çizginin dörde eşit olması değil, ters eğik çizgiyi aşağıdaki gibi bir karakterle izlediğinizde ?, ikisi birlikte iki karakter olarak gelir, çünkü \?tanınan bir kaçış dizisi değildir.


6
Hoşgörünün tam tersi. Yumuşak, çoğu kişinin "ihtiyacı olmayan bir karaktere ters eğik çizgi koyarsanız, ters eğik çizgi hiçbir şey yapmaz" davranışıdır. Başka bir kuralla birlikte (ters eğik çizgi alfasayısallar onları özel kılabilir, ancak ters eğik çizgi onu her zaman özel kılar), hangi karakterlerin özel olarak olduğunu bilmenize gerek kalmadan tüm noktalamaları ters eğik çizgi ile ters bölüp kullanarak bir dizeyi güvenli bir şekilde tanımlayabileceğiniz çok güzel bir özellik elde edersiniz. interpeted - Python'da eksik olan bir özellik.
hobbs

24
Hayır, hoşgörünün tersi, tanınmayan bir ters eğik çizgi kaçışını kullandığınızda bir hata ortaya çıkarmak olacaktır. (Derlenen hemen hemen her dilin yaptığı gibi. Python'un dizgi işlemesinin temelde "C gibi olduğunu, ancak geçersiz ters eğik çizgi kaçışları verildiğinde patlamamamız dışında" olduğunu unutmayın) Ayrıca, dil ne olursa olsun bir dizede kaçması gereken yalnızca iki karakter vardır - sınırlayıcı olarak kullandığınız her neyse ve ters eğik çizginin kendisi. İkisini de hatırlamanın zor olduğu argümanını anlamıyorum.
Daniel Martin

@DanielMartin, sınırlayıcının kendi kaçış karakteri olarak işlev gördüğü bazı diller vardır (örneğin 'escape''d'). Oradaki diğer karakterleri hatırlamanıza bile gerek yok!
SztupY

1
Oh bekleyin, sanırım standart Pascal da bu sistemi kullandı - bkz. Nyx.net/~gthompso/self_pasc.txt
Daniel Martin

1
@DanielMartin SQL de.
Random832

30

Bunun nedeni, ters eğik çizginin, kombinasyon geçerli bir kaçış sırasını temsil etmesi durumunda, hemen ardından gelen karakter (ler) için bir çıkış karakteri görevi görmesidir. Bir düzine kaçış dizisi burada listelenmiştir . Bunlar satırsonu \n, yatay sekme \t, satır başı gibi bariz olanları \rve \N{...}örneğin \N{WAVY DASH}unicode karakterini temsil eden adlandırılmış unicode karakterleri gibi daha belirsiz olanları içerir \u3030. Yine de kilit nokta, kaçış dizisi bilinmiyorsa, karakter dizisinin dizede olduğu gibi bırakılmasıdır.

Sorunun bir kısmı da Python yorumlayıcı çıktısının sizi yanıltması olabilir. Bunun nedeni, ters eğik çizgilerin görüntülendiğinde öncelenmesidir. Ancak, bu dizeleri yazdırırsanız , fazladan ters eğik çizgilerin kaybolduğunu göreceksiniz.

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

Özel örnekleriniz için, ilk durumda '?\\\?', birincisi \ikinci ters eğik çizgiden tek bir ters eğik çizgi bırakarak kaçar, ancak üçüncü ters eğik çizgi \?, geçerli bir kaçış dizisi olmadığından ters eğik çizgi olarak kalır . Sonuç olarak ortaya çıkan dize ?\\?.

İkinci durum için '?\\\\?', ilk ters eğik çizgi ikinciden ve üçüncü ters eğik çizgi dördüncüden kaçarak dizeyle sonuçlanır ?\\?.

İşte bu yüzden üç ters eğik çizgi dört ile aynıdır:

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

3 ters eğik çizgiye sahip bir dize oluşturmak istiyorsanız, her ters eğik çizgiden kaçabilirsiniz:

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

veya "ham" dizeleri daha anlaşılır bulabilirsiniz:

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

Bu, dizge değişmezi için kaçış dizisi işlemeyi döndürür. Daha fazla ayrıntı için Dize Değişmezlerine bakın.


Haklısın '?\\\?'=='?\\?'verir Falsebunu yanlış yazmış. '?\\\?'=='?\\\\?'Sorunun da gösterdiği gibi olmalı , ben onu düzelttim.
kozooh

13

Çünkü \xbir karakter dizisiyle, zaman xgibi özel backslashable karakterlerden biri değil n, r, t, 0, vb sonra bir ters eğik çizgi ve bir dizeye değerlendirir x.

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

7

Python sözcük analizi sayfasından, dize değişmezleri altındaki: https://docs.python.org/2/reference/lexical_analysis.html

Tüm tanınan kaçış dizilerini listeleyen bir tablo var.

\\ bir kaçış dizisidir, === \

\? bir kaçış dizisi değil ve === \?

bu yüzden '\\', '\\' ve ardından '\\' ve '\\' (iki çıkış karakterli \)

ve '\\', '\\' ve ardından '\' ve yine '\\' (bir çıkış \ ve bir ham \)

Ayrıca, python'un diğer bazı dillerden farklı olarak bir dizgeyi çevreleyen tek ve çift tırnak arasında ayrım yapmadığı da unutulmamalıdır.

Dolayısıyla 'String' ve "String" python'da tamamen aynıdır, kaçış dizilerinin yorumlanmasını etkilemezler.


1

mhawke'nin cevabı hemen hemen onu kapsıyor, ben sadece onu daha kısa bir biçimde ve bu davranışı gösteren minimal örneklerle yeniden ifade etmek istiyorum.

Sanırım eklenecek bir şey, kaçış işleminin soldan sağa doğru hareket etmesi, böylece \nönce ters eğik çizgiyi bulur ve sonra kaçacak bir karakter arar, sonra nonu bulur ve kaçar; \\nilk ters eğik çizgiyi bulur, ikinciyi bulur ve ondan kaçar, sonra bulur nve gerçek bir n olarak görür; \?ters eğik çizgiyi bulur ve kaçmak için bir karakter arar, ?hangisini kaçılamayacağını bulur ve bu nedenle \birebir ters eğik çizgi olarak değerlendirilir.

Mhawke'nin belirttiği gibi, buradaki anahtar, etkileşimli yorumlayıcının bir dizeyi görüntülerken ters eğik çizgiden kaçmasıdır. Bunun nedeninin, yorumlayıcıdan kod düzenleyiciye kopyalanan metin dizelerinin geçerli python dizeleri olmasını sağlamak olduğunu tahmin ediyorum. Bununla birlikte, bu durumda bu kolaylık ödeneği kafa karışıklığına neden olur.

>>> 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
\\?
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.