Python'un ham dize değişmezleri neden tek bir ters eğik çizgi ile bitmiyor?


179

Teknik olarak , belgelerde açıklandığı gibi tek sayıda ters eğik çizgi .

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

Ayrıştırıcı, ham dizelerdeki ters eğik çizgileri normal karakterler olarak ele alabilir gibi görünüyor (ham dizelerin hepsi hakkında değil mi?), Ama muhtemelen belirgin bir şey eksik.


8
Bu şimdi bir SSS gibi görünüyor . soruyu sorduğunuzda olmayabilir. alıntı yaptığınız dokümanlar hemen hemen aynı şeyi söylüyor, ama ben sadece başka bir belge kaynağı eklemek düşündüm.
oob

Yanıtlar:


124

Nedeni, bu bölümün kalın harflerle vurgulanmış bölümünde açıklanmıştır:

Dize tırnak işaretleri ters eğik çizgi ile kaçabilir, ancak ters eğik çizgi dizede kalır; örneğin, r"\""iki karakterden oluşan geçerli bir dize değişmezidir: ters eğik çizgi ve çift tırnak; r"\"geçerli bir dize değişmez değeri değildir (ham dize bile tek sayıda ters eğik çizgi ile bitemez). Özellikle, ham dize tek bir ters eğik çizgi ile bitemez (ters eğik çizgi aşağıdaki alıntı karakterinden kaçacağı için). Ayrıca, yeni satırın izlediği tek ters eğik çizginin, satır devamı olarak değil, dizenin bir parçası olarak bu iki karakter olarak yorumlandığını unutmayın.

Ham dizeler% 100 ham değil, hala bazı temel ters eğik çizgi işleme var.


21
Oh vay ... bu çok garip. İyi yakaladın. R '\' '== "\\'" mantıklıdır, ancak yine de kaçış karakterinin kaybolmadan bir etkisi olması gariptir.
cdleary

2
@ihightower bu, dosya sistemi yolları için işe yarayabilir, ancak ters eğik çizginin başka kullanımları da vardır. Ve dosya sistemi yolları için ayırıcıyı kodlamayın. 'Os.path.sep' kullanın ya da 'os.path'in daha üst düzey özelliklerini kullanın. (Veya mevcutsa 'pathlib')
oefe

5
Not: Geçici çözüm, bitişik değişmez birleşimi kullanmaktır. r"foo\bar\baz" "\\"(belirsizse parensleri sarın) derleme zamanında tek bir değişmez oluşturur, ilk kısmı ham ve yalnızca son küçük bit ham olmayan, sondaki ters eğik çizgiye izin verir.
ShadowRanger

2
IMO bu, neden bu şekilde tasarlandığını söylemeden soruyu (neye izin verilir / neyin işe yarayacağını ve neyin işe yaramayacağını) yeniden ifade eder. Nedenini açıklayan bir SSS girişi var (ham dizeler belirli bir amaç için tasarlandı ve bu amaç bağlamında mantıklı).
ShreevatsaR

3
Ham dizelerin anlamı nedir? Kavramın gölgeli bir uygulaması gibi görünüyor.
Matthew James Briggs

101

Python'un ham dizeleri hakkındaki tüm yanlış kanı, çoğu insanın ters eğik çizginin (ham bir dize içinde) diğerleri gibi normal bir karakter olduğunu düşünmesidir. O değil. Anlaşılması gereken anahtar bu python'un öğretici dizisidir:

Bir ' r ' veya ' R ' öneki mevcutsa, dizeye ters eğik çizgiyi izleyen bir karakter değişmeden dahil edilir ve tüm ters eğik çizgiler dizede bırakılır

Yani ters eğik çizgi izleyen herhangi bir karakter olan ham dizenin parçası. Ayrıştırıcı bir ham dizeye (Unicode olmayan bir) girip bir ters eğik çizgi ile karşılaştığında 2 karakter olduğunu (bir ters eğik çizgi ve onu izleyen bir karakter) bilir.

Bu yoldan:

r'abc \ d' içerir , a, b, c, \, d

r'abc \ 'd' içerir , a, b, c, \,' d

r'abc \ '' içerir , a, b, c, \, '

ve:

r'abc \ ' , a, b, c, \,' içerir, ancak şu anda sonlandırma teklifi yoktur.

Son durum, belgelere göre, bir ayrıştırıcının, yukarıda gördüğünüz son teklifin dizenin bir parçası olduğu için kapanış teklifini bulamadığını gösterir, yani ters eğik çizgi, dizgi kapanış karakterini 'yiyip bitireceği için burada son olamaz.


8
Bu aslında kabul edilen cevaptan daha açıktır. Güzel arıza.
Mad Physicist

4
Ben de bu kabul edilen cevap daha belirgin buluyorum, ve ben de bir fizikçi olur
xdavidliu

22

Bu şekilde! Bunu pitondaki küçük kusurlardan biri olarak görüyorum!

Bunun için iyi bir neden olduğunu düşünmüyorum, ama kesinlikle ayrışmıyor; Son karakter olarak \ ile ham dizeleri ayrıştırmak gerçekten çok kolay.

Yakalama, eğer ham karakter dizisindeki son karakter olmasına izin verirseniz, "ham karakter dizisinin içine" koyamazsınız. Son karakter olarak izin vermek yerine \ 'izin vermekle birlikte gitmiş gibi görünüyor.

Ancak, bu herhangi bir soruna neden olmamalıdır.

Windows klasörü yollarını kolayca yazamamaktan c:\mypath\endişe ediyorsanız, endişelenmeyin, çünkü bunları şu şekilde temsil edebilirsiniz r"C:\mypath"ve bir alt dizin adı eklemeniz gerekiyorsa, dizeyi birleştirme ile yapmayın, çünkü yine de bunu yapmanın doğru yolu değil! kullanımos.path.join

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

2
İyi yardımcı malzeme. :-) Şeytan'ın savunucusu olsa da: bazen yol ayırıcıyı ekleyerek dosya yollarını dizin yollarından ayırmak istersiniz. Os.path.join ile ilgili güzel bir şey, onları daraltacağıdır: assert os.path.join ('/ home / cdleary /', 'foo /', 'bar /') == '/ home / cdleary / foo / bar / '
cdleary

Yine de (teknik) bir fark yaratmaz! os.path.isdir, belirli bir yolun bir dizin (klasör) olup olmadığını söyler
hasen

2
Evet, sadece kodu okuyan birine yolun dizin mi yoksa dosya mı olacağını beklemek.
cdleary

Windows'taki kural, dosyaların her zaman bir uzantısına sahip olmasıdır. (normal şartlar altında) c: \ path \ data
hasen

5
..ya da onları "c: / mypath" olarak temsil edebilir ve ters eğik
çizginizi

14

Ham bir dizgeyi eğik çizgi ile bitirebilmeniz için bu numarayı kullanmanızı öneririm:

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

14

Başka bir hile, "\" olarak değerlendirilirken chr (92) kullanmaktır.

Son zamanlarda bir dizi ters eğik çizgi temizlemek zorunda kaldı ve aşağıdaki hile yaptı:

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

Bunun "neden" ile ilgilenmediğini, ancak iş parçacığının acil bir soruna çözüm arayan birçok insanı çektiğinin farkındayım.


Peki ya orijinal dize ters eğik çizgi içeriyorsa?
Joseph Redfern

2
chr (92) korkunç, muhtemelen kullanmak daha iyi "\\"(ters eğik çizgi ile ham olmayan dize)
clemep

9

\ "Ham dizginin içine izin verildiğinden, dizgi değişmezinin sonunu tanımlamak için kullanılamaz.

Neden ilk "ile karşılaştığınızda dize hazır bilgisini ayrıştırmayı bırakmıyorsunuz?

Durum böyleyse, dizge değişmezinin içinde \ "kullanılmasına izin verilmezdi.


1
Kesinlikle. Python tasarımcıları muhtemelen iki alternatifin olasılığını değerlendirdi: \"çift ​​tırnaklı ham dize içinde herhangi bir yerde iki karakterli dizi , çift tırnaklı ham dize sonunda OR \. Kullanım istatistikleri, iki karakter dizisini, sondaki tek karakter dizisine karşı her yerde desteklemelidir.
ocaklar

3

r'\'Sözdizimsel neden yanlış olmasının nedeni , dize ifadesi ham olmasına rağmen, kullanılan tırnak işaretlerinin (tekli veya çiftli) her zaman kaçmak zorunda olmalarıdır, çünkü tırnakların sonunu işaretlerler. Bu nedenle, tek tırnak içine alınmış dize içinde tek bir alıntı ifade etmek istiyorsanız, kullanmaktan başka bir yol yoktur \'. Aynı şey çift tırnak için de geçerlidir.

Ancak şunları kullanabilirsiniz:

'\\'

4
'Neden' :-) cevap
vermez

2

O zamandan beri cevaplarını silmiş olan başka bir kullanıcı (kredilendirilmek isteyip istemediklerinden emin değil) Python dil tasarımcılarının aynı ayrıştırma kurallarını kullanarak ve çıkış karakterlerini sonradan düşünülecek şekilde ham forma genişleterek çözümleyici tasarımını basitleştirebileceğini önerdi. (değişmez değer ham olarak işaretlenmişse).

Bunun ilginç bir fikir olduğunu düşündüm ve bunu gelecek nesiller için topluluk wiki'si olarak ekliyorum.


Ancak, iki ayrı dize-değişmez-ayrıştırıcı kod yoluna sahip olmaktan kaçınmanıza izin verebilir.
cdleary

2

Rolüne rağmen, ham dize bile tek bir ters eğik çizgi ile bitemez, çünkü ters eğik çizgi aşağıdaki alıntı karakterinden kaçar - yine de dizeye gömmek için çevresindeki tırnak karakterinden kaçmanız gerekir. Yani, r "... \" geçerli bir dize değişmez değeri değildir - ham dize tek sayıda ters eğik çizgi ile bitemez.
Ham dizeyi tek bir ters eğik çizgiyle sonlandırmanız gerekiyorsa, ikisini kullanabilir ve ikincisini dilimleyebilirsiniz.


1

C'den geldiğimde, tek bir \ 'ın yeni satırlar, sekmeler ve tırnak işaretleri gibi özel karakterleri dizelere koymanıza izin veren kaçış karakteri olarak çalıştığı oldukça açık.

Bu gerçekten \ 'son karakter olarak izin vermiyor çünkü kaçacak ve ayrıştırıcıyı boğacak. Ama daha önce de belirtildiği gibi' yasal.


1
Evet - sorunun özü, ham dizelerin \ 'bir kaçış dizisinin başlangıcı yerine gerçek olarak davranmasıydı. Garip olan şey, gerçek bir karakter olarak görülmesine rağmen, alıntı yapmak için hala kaçış özelliklerine sahip olmasıdır.
cdleary

1

bazı ipuçları :

1) yol için ters eğik çizgi kullanmanız gerekiyorsa, standart python modülü os.path arkadaşınızdır. Örneğin :

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

2) içinde ters eğik çizgi bulunan dizeler oluşturmak istiyorsanız, ancak dizenizin sonunda ters eğik çizgi olmadan ham dize arkadaşınızdır (değişmez dizeden önce 'r' önekini kullanın). Örneğin :

r'\one \two \three'

3) X değişkenindeki bir dizeyi ters eğik çizgi ile önek yapmanız gerekirse, bunu yapabilirsiniz:

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) sonunda ters eğik çizgi bulunan bir dize oluşturmanız gerekirse, 2. ve 3. ipuçlarını birleştirin:

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

şimdi lilypond_statement içeriyor "\DisplayLilyMusic \upper"

Yaşasın piton! :)

n3on


1
Bunların hiçbiri "neden" sorusuna cevap vermez, ancak # 3 ve # 4 kullanılmamalıdır. Dizeleri dilimlemek ve eklemek genellikle kötü bir uygulamadır ve # 3 (bu iyi çalışır) için r '\ dummy' ve '' .join ([r '\ DisplayLilyMusic', r '\ upper']) 'ı # 4'e tercih etmelisiniz.
cdleary

1
Bunun nedeni, dizelerin değişmez ve her dilim / birleştirme tipik olarak atılan yeni bir değişmez dize nesnesi oluşturur. Hepsini biriktirmek ve str.join (bileşenler) ile bir adımda bir araya gelmek daha iyidir
CDLeary

Hata! # 3 için ne demek istediğini yanlış anlamışsın. Ben basit bir '\\' + X sadece dilim için bir dize oluşturmak için tercih olduğunu düşünüyorum.
cdleary

Sadece bulmak os.path.normpathkuyruk ters eğik çizgiyi kaldıracak ... O zaman dosya adını yola nasıl kapatmalıyım ...
Jing He

0

Bu sorunla karşılaştım ve bazı durumlar için iyi olan kısmi bir çözüm buldum. Python tek bir ters eğik çizgi ile bir dizeyi bitiremese de, serileştirilebilir ve sonunda tek bir ters eğik çizgi ile bir metin dosyasına kaydedilebilir. Bu nedenle, ihtiyacınız olan şey bir metni bilgisayarınızda tek ters eğik çizgi ile kaydetmekse, şunlar mümkündür:

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, python'un json kütüphanesini kullanarak dökerseniz json ile çalışmaz.

Son olarak, Spyder ile çalışıyorum ve değişken explorer'daki ismine çift tıklayarak değişkeni örümceğin metin düzenleyicisinde açarsam, tek bir ters eğik çizgi ile sunulur ve panoya bu şekilde kopyalanabilir ( çoğu ihtiyaçları için çok yararlı ama belki bazıları için ..).

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.