เหตุใดตัวอักษรสตริงดิบของ Python จึงไม่สามารถลงท้ายด้วยเครื่องหมายทับขวาเดียวได้


179

เทคนิคใดเลขคี่ของ backslashes ที่อธิบายไว้ในเอกสาร

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

ดูเหมือนว่า parser สามารถจัดการแบ็กสแลชในสายอักขระดิบเป็นตัวอักษรปกติได้ (ไม่ใช่ว่าเป็นสตริงที่เกี่ยวกับอะไร) แต่ฉันอาจขาดอะไรบางอย่างที่ชัดเจน


8
ลักษณะเช่นนี้ในขณะนี้เป็นคำถามที่พบบ่อย อาจไม่ได้เมื่อคุณถามคำถาม ฉันรู้ว่าเอกสารที่คุณอ้างถึงพูดค่อนข้างเหมือนกัน แต่ฉันแค่คิดว่าฉันจะเพิ่มแหล่งเอกสารอื่น
oob

คำตอบ:


124

เหตุผลอธิบายในส่วนของส่วนที่ฉันเน้นเป็นตัวหนา:

คำพูดสตริงสามารถหนีด้วยแบ็กสแลชแต่แบ็กสแลชยังคงอยู่ในสตริง; ตัวอย่างเช่นr"\""เป็นสตริงตัวอักษรที่ถูกต้องซึ่งประกอบด้วยอักขระสองตัวคือเครื่องหมายแบ็กสแลชและเครื่องหมายคำพูดคู่ r"\"ไม่ใช่ตัวอักษรสตริงที่ถูกต้อง (แม้สตริงดิบจะไม่สามารถลงท้ายด้วยแบ็กสแลชจำนวนคี่) สตริงดิบไม่สามารถสิ้นสุดในแบ็กสแลชเดี่ยว (เนื่องจากแบ็กสแลชจะหนีจากอักขระเครื่องหมายคำพูดต่อไปนี้) โปรดทราบว่าเครื่องหมายแบ็กสแลชเดี่ยวตามด้วยบรรทัดใหม่จะถูกตีความว่าเป็นอักขระสองตัวที่เป็นส่วนหนึ่งของสตริงไม่ใช่เป็นการดำเนินการต่อเนื่องของบรรทัด

ดังนั้นสตริงดิบไม่ใช่ดิบ 100% จึงยังมีการประมวลผลแบ็กสแลชพื้นฐาน


21
โอ้ว้าว ... มันแปลก รับได้สวย. ทำให้รู้สึกว่า r '\' '== "\\'" แต่ก็ยังแปลกที่ตัวละครหลบหนีมีผลโดยไม่หายไป
cdleary

2
@ihightower อาจทำงานกับพา ธ ของระบบไฟล์ แต่มีการใช้แบ็กสแลชอื่น ๆ และสำหรับเส้นทางของระบบไฟล์อย่าทำการ hardcode ตัวคั่น ใช้ 'os.path.sep' หรือดีกว่าฟีเจอร์ระดับสูงกว่าของ 'os.path' (หรือ 'pathlib' หากมี)
ช่วง

5
หมายเหตุ: วิธีแก้ปัญหาคือใช้การเรียงตัวอักษรที่อยู่ติดกัน r"foo\bar\baz" "\\"(ห่อใน parens หากคลุมเครือ) จะสร้างตัวอักษรเดียวในเวลารวบรวมส่วนแรกซึ่งเป็นข้อมูลดิบและบิตจิ๋วสุดท้ายเท่านั้นที่ไม่ใช่แบบดิบเพื่อให้แบ็กสแลชต่อท้าย
ShadowRanger

2
IMO เพียงแค่นำคำถามนี้กลับมาใช้ใหม่ (สิ่งที่ได้รับอนุญาต / ทำงานได้และสิ่งที่ไม่ได้) โดยไม่บอกว่าทำไมจึงออกแบบมาในลักษณะนี้ มีรายการคำถามที่พบบ่อยซึ่งอธิบายว่าทำไม (สตริงดิบถูกออกแบบมาเพื่อวัตถุประสงค์เฉพาะและมันสมเหตุสมผลในบริบทของวัตถุประสงค์นั้น)
ShreevatsaR

3
จุดของสตริงดิบคืออะไร? ดูเหมือนว่าการใช้แนวคิดที่ร่มรื่น
Matthew James Briggs

101

ความเข้าใจผิดทั้งหมดเกี่ยวกับสตริงดิบของไพ ธ อนคือคนส่วนใหญ่คิดว่าแบ็กสแลช (ภายในสตริงดิบ) เป็นเพียงตัวอักษรปกติเหมือนกับคนอื่น ๆ ทั้งหมด มันไม่ใช่. กุญแจสำคัญในการทำความเข้าใจคือลำดับการสอนของงูใหญ่นี้:

เมื่อคำนำหน้า' r ' หรือ ' R ' มีอยู่อักขระที่ตามหลังเครื่องหมายทับขวาจะรวมอยู่ในสตริงโดยไม่มีการเปลี่ยนแปลงและเครื่องหมายแบ็กสแลชทั้งหมดจะอยู่ในสตริง

ดังนั้นอักขระใด ๆ ที่ตามหลังแบ็กสแลชจึงเป็นส่วนหนึ่งของสตริงดิบ เมื่อ parser ป้อนสตริงดิบ (ไม่ใช่ Unicode หนึ่ง) และพบแบ็กสแลชมันรู้ว่ามีอักขระ 2 ตัว (แบ็กสแลชและอักขระที่ตามมา)

ทางนี้:

r'abc \ d 'ประกอบด้วยa, b, c, \, d

r'abc \ 'd'ประกอบด้วยa, b, c, \, ', d

r'abc \ ''ประกอบด้วยa, b, c, \, '

และ:

r'abc \ 'ประกอบด้วยa, b, c, \,'แต่ไม่มีการยกเลิกคำพูดในตอนนี้

กรณีสุดท้ายแสดงให้เห็นว่าตามเอกสารตอนนี้ตัวแยกวิเคราะห์ไม่สามารถหาเครื่องหมายอัญประกาศปิดได้เนื่องจากคำพูดสุดท้ายที่คุณเห็นข้างต้นเป็นส่วนหนึ่งของสตริงนั่นคือเครื่องหมายแบ็กสแลชไม่สามารถอยู่ที่นี่ได้


8
นี่เป็นจริงที่ชัดเจนกว่าคำตอบที่ยอมรับ การวิเคราะห์ที่ดี
นักฟิสิกส์บ้า

4
ฉันก็พบว่ามันชัดเจนกว่าคำตอบที่ยอมรับและฉันก็เป็นนักฟิสิกส์ด้วย
xdavidliu

22

นั่นคือวิธีที่มันเป็น! ฉันเห็นว่ามันเป็นหนึ่งในข้อบกพร่องเล็ก ๆ เหล่านั้นในหลาม!

ฉันไม่คิดว่ามันมีเหตุผลที่ดีสำหรับมัน แต่ก็ไม่ได้แยกวิเคราะห์อย่างแน่นอน มันง่ายมากในการแยกวิเคราะห์สตริงที่มี \ เป็นอักขระตัวสุดท้าย

การจับคือถ้าคุณอนุญาตให้ \ เป็นอักขระตัวสุดท้ายในสตริง raw คุณจะไม่สามารถใส่ "ในสตริง raw ได้ดูเหมือนว่า Python จะอนุญาตให้ใช้" แทนที่จะอนุญาตให้ \ เป็นอักขระตัวสุดท้าย

อย่างไรก็ตามสิ่งนี้ไม่ควรทำให้เกิดปัญหาใด ๆ

หากคุณกังวลว่าจะไม่สามารถเขียนเส้นทางของโฟลเดอร์ windows ได้อย่างง่ายดายเช่นc:\mypath\นั้นไม่ต้องกังวลเพราะคุณสามารถเป็นตัวแทนพวกเขาเป็นr"C:\mypath"และถ้าคุณต้องการผนวกชื่อไดเรกทอรีย่อยไม่ต้องใช้การต่อสตริงด้วย มันไม่ใช่วิธีที่เหมาะสมที่จะทำ! ใช้os.path.join

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

2
วัสดุเสริมที่ดี :-) ผู้สนับสนุนของ Devil: บางครั้งคุณต้องการแยกความแตกต่างของเส้นทางไฟล์จากเส้นทางไดเรกทอรีโดยผนวกตัวแยกเส้นทาง สิ่งที่ดีเกี่ยวกับ os.path.join ก็คือมันจะยุบมัน: assert os.path.join ('/ home / cdleary /', 'foo /', 'bar /') == '/ home / cdleary / foo / bar / '
cdleary

มันไม่ได้สร้างความแตกต่าง (ทางเทคนิค)! os.path.isdir จะบอกคุณว่าเส้นทางบางอย่างเป็นไดเรกทอรี (โฟลเดอร์)
Hasen

2
ใช่มันเป็นเพียงการระบุให้คนที่กำลังอ่านรหัสไม่ว่าคุณจะคาดหวังว่าเส้นทางจะเป็นไดเรกทอรีหรือไฟล์
cdleary

ข้อตกลงใน windows คือไฟล์มีส่วนขยายเสมอ ไม่น่าเป็นไปได้เลย (ภายใต้สถานการณ์ปกติ) ที่จะมีไฟล์ข้อความที่มีพา ธ เช่น c: \ path \ data
hasen

5
..or คุณสามารถเป็นตัวแทนของพวกเขาเป็น "C: / mypath" และลืม woes ทับขวาของคุณทั้งหมด :-)
จอห์น Fouhy

14

เพื่อให้คุณจบสตริง raw ด้วยสแลชฉันแนะนำให้คุณใช้เคล็ดลับนี้:

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

14

เคล็ดลับอีกอย่างคือการใช้ chr (92) ตามที่ประเมินเป็น "\"

เมื่อเร็ว ๆ นี้ฉันต้องล้างแบ็กสแลชจำนวนหนึ่งและเคล็ดลับต่อไปนี้ก็ทำได้:

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

ฉันรู้ว่านี่ไม่ได้ดูแล "ทำไม" แต่เธรดดึงดูดผู้คนมากมายที่กำลังมองหาวิธีการแก้ไขปัญหาที่เกิดขึ้นทันที


แต่ถ้าสตริงเดิมมีแบ็กสแลช?
โจเซฟ Redfern

2
chr (92) ปิดบัง"\\"
สุดขีด

9

เนื่องจากอนุญาตให้ \ "ภายในสตริง raw จากนั้นไม่สามารถใช้เพื่อระบุจุดสิ้นสุดของตัวอักษรสตริง

ทำไมไม่หยุดแยกสตริงตัวอักษรเมื่อคุณพบ "ครั้งแรก?

หากเป็นเช่นนั้น \ "จะไม่ได้รับอนุญาตภายในสตริงตัวอักษร แต่เป็น


1
เผง ผู้ออกแบบ Python จะประเมินความเป็นไปได้ของทางเลือกสองทาง: ลำดับอักขระสองตัว\"ที่ใดก็ได้ภายในสตริง raw ที่มีเครื่องหมายคำพูดคู่หรือ OR \ ที่ส่วนท้ายของสตริง raw ที่มีเครื่องหมายคำพูดคู่ สถิติการใช้งานจะต้องเป็นไปตามลำดับอักขระสองตัวเทียบกับลำดับอักขระหนึ่งตัวในตอนท้าย
เตาแก๊ส

3

เหตุผลที่ทำไมการr'\'สร้างประโยคที่ไม่ถูกต้องก็คือแม้ว่านิพจน์สตริงนั้นจะมีความหมายว่าราคาที่ใช้ (เดี่ยวหรือสองครั้ง) จะต้องหลีกหนีเพราะจะทำเครื่องหมายที่ส่วนท้ายของราคา ดังนั้นถ้าคุณต้องการที่จะแสดงคำพูดเดียวภายในสายยกเดียวไม่มีวิธีอื่น ๆ \'กว่าการใช้ เช่นเดียวกับคำพูดคู่

แต่คุณสามารถใช้:

'\\'

4
ไม่ตอบ 'ทำไม' :-)
cdleary

2

ผู้ใช้รายอื่นที่ลบคำตอบของพวกเขา (ไม่แน่ใจว่าพวกเขาต้องการให้เครดิต) แนะนำว่านักออกแบบภาษา Python อาจสามารถทำให้การออกแบบตัวแยกวิเคราะห์ง่ายขึ้นโดยใช้กฎการแยกวิเคราะห์เดียวกันและขยายตัวอักขระหนีออกมาให้อยู่ในรูปแบบใหม่ (ถ้าตัวอักษรถูกทำเครื่องหมายเป็นดิบ)

ฉันคิดว่ามันเป็นความคิดที่น่าสนใจและรวมเอาไว้เป็นวิกิของชุมชนเพื่อลูกหลาน


แต่มันอาจช่วยให้คุณหลีกเลี่ยงการใช้เส้นทางรหัส string-literal-parser แยกกันสองเส้นทาง
cdleary

2

แม้จะมีบทบาทแล้วก็ตามแม้สตริงดิบจะไม่สามารถลงท้ายด้วยเครื่องหมายทับขวาเดียวได้เนื่องจากเครื่องหมายแบ็กสแลชจะหนีอักขระคำพูดต่อไปนี้ - คุณยังต้องหลีกเลี่ยงอักขระเครื่องหมายคำพูดล้อมรอบเพื่อฝังไว้ในสตริง นั่นคือ r "... \" ไม่ใช่ตัวอักษรสตริงที่ถูกต้องสตริงดิบไม่สามารถลงท้ายด้วยแบ็กสแลชจำนวนคี่
หากคุณต้องการจบสตริงดิบด้วยแบ็กสแลชเดี่ยวคุณสามารถใช้สองและแบ่งวินาที


1

มาจาก C มันค่อนข้างชัดเจนสำหรับฉันที่ว่า \ ทำงานเป็นอักขระตัวช่วยให้คุณใส่อักขระพิเศษเช่นการขึ้นบรรทัดใหม่แท็บและเครื่องหมายคำพูดลงในสตริง

ที่ไม่อนุญาต \ เป็นตัวละครตัวสุดท้ายเพราะมันจะหนี "และทำให้ parser ทำให้หายใจไม่ออก แต่ตามที่กล่าวไว้ก่อนหน้านี้ \ ถูกกฎหมาย


1
ใช่ - หัวใจของปัญหาคือสายอักขระดิบปฏิบัติต่อ \ เป็นตัวอักษรแทนที่จะเป็นจุดเริ่มต้นของลำดับการหลบหนี สิ่งที่แปลกคือมันยังคงมีคุณสมบัติการหลบหนีสำหรับการอ้างอิงแม้จะได้รับการปฏิบัติเหมือนเป็นตัวอักษร
cdleary

1

เคล็ดลับบางอย่าง:

1) ถ้าคุณต้องการจัดการแบ็กสแลชสำหรับพา ธ ดังนั้นโมดูลหลามมาตรฐาน os.path คือเพื่อนของคุณ ตัวอย่างเช่น :

os.path.normpath ( 'C: / folder1 /')

2) ถ้าคุณต้องการสร้างสตริงด้วยแบ็กสแลชในนั้น แต่ไม่มีแบ็กสแลชที่ส่วนท้ายของสตริงสตริงดิบคือเพื่อนของคุณ (ใช้คำนำหน้า 'r' ก่อนสตริงตัวอักษรของคุณ) ตัวอย่างเช่น :

r'\one \two \three'

3) ถ้าคุณต้องการนำหน้าสตริงในตัวแปร X ด้วยแบ็กสแลชจากนั้นคุณสามารถทำสิ่งนี้:

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) ถ้าคุณต้องการสร้างสตริงด้วยแบ็กสแลชที่ท้ายให้รวมทิป 2 และ 3:

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

ตอนนี้มี lilypond_statement "\DisplayLilyMusic \upper"

หลามอยู่นาน! :)

n3on


1
สิ่งเหล่านี้ไม่ตอบคำถาม "ทำไม" แต่ไม่ควรใช้ # 3 และ # 4 โดยทั่วไปการแบ่งและการเพิ่มสตริงเป็นการฝึกที่ไม่ดีและคุณควรเลือก r '\ dummy' สำหรับ # 3 (ซึ่งใช้งานได้ดี) และ '' .join ([r '\ DisplayLilyMusic', r '\ upper']) ถึง # 4
cdleary

1
เหตุผลที่สตริงนั้นไม่เปลี่ยนรูปและแต่ละส่วน / การต่อเรียงสร้างวัตถุสตริงที่ไม่เปลี่ยนรูปแบบใหม่ซึ่งโดยทั่วไปจะถูกทิ้ง ดีกว่าที่จะสะสมพวกเขาทั้งหมดและร่วมกับพวกเขาด้วยกันในขั้นตอนเดียวกับ str.join (ส่วนประกอบ)
cdleary

โอ้โหเข้าใจผิดว่าคุณหมายถึงอะไรใน # 3 ฉันคิดว่ามี '\\' + X ง่ายกว่าต้องการสร้างสตริงเพียงเพื่อฝาน
cdleary

เพียงแค่ค้นหาos.path.normpathจะลบเครื่องหมายแบ็กสแลชที่หางออกไป ... จากนั้นฉันจะต่อท้ายชื่อไฟล์อย่างไรในเส้นทาง ...
จิงเหอ

0

ฉันพบปัญหานี้และพบวิธีแก้ปัญหาบางส่วนซึ่งดีสำหรับบางกรณี แม้ว่า python จะไม่สามารถจบสตริงด้วยแบ็กสแลชเดี่ยว แต่ก็สามารถทำให้เป็นอนุกรมและบันทึกในไฟล์ข้อความด้วยแบ็กสแลชเดี่ยวที่ส่วนท้าย ดังนั้นหากสิ่งที่คุณต้องการคือการบันทึกข้อความด้วยแบ็กสแลชเดี่ยวบนคอมพิวเตอร์ของคุณก็เป็นไปได้:

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 มันไม่ทำงานกับ json ถ้าคุณดัมพ์โดยใช้ไลบรารี json ของ python

ในที่สุดฉันทำงานกับ Spyder และฉันสังเกตเห็นว่าถ้าฉันเปิดตัวแปรในโปรแกรมแก้ไขข้อความของ spider โดยคลิกสองครั้งที่ชื่อของมันในตัวแปร explorer มันจะถูกแสดงด้วยแบ็กสแลชเดี่ยวและสามารถคัดลอกไปยังคลิปบอร์ดได้ มีประโยชน์มากสำหรับความต้องการส่วนใหญ่ แต่อาจจะสำหรับบาง .. )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.