จะยกเลิกการหลีกเลี่ยงสตริงที่ใช้เครื่องหมายแบ็กสแลชได้อย่างไร


101

สมมติว่าฉันมีสตริงซึ่งเป็นเวอร์ชันที่ใช้เครื่องหมายแบ็กสแลชของสตริงอื่น มีวิธีง่ายๆใน Python เพื่อ unescape สตริงหรือไม่? ตัวอย่างเช่นฉันทำได้:

>>> escaped_str = '"Hello,\\nworld!"'
>>> raw_str = eval(escaped_str)
>>> print raw_str
Hello,
world!
>>> 

อย่างไรก็ตามเกี่ยวข้องกับการส่งสตริง (อาจไม่น่าเชื่อถือ) ไปยัง eval () ซึ่งเป็นความเสี่ยงด้านความปลอดภัย มีฟังก์ชันใน lib มาตรฐานที่รับสตริงและสร้างสตริงโดยไม่มีผลกระทบด้านความปลอดภัยหรือไม่?

คำตอบ:


138
>>> print '"Hello,\\nworld!"'.decode('string_escape')
"Hello,
world!"

9
มีบางอย่างที่เข้ากันได้กับ python 3 หรือไม่?
thejinx0r

3
@ thejinx0r: ดูได้ที่นี่: stackoverflow.com/questions/14820429/…
ChristopheD

30
โดยทั่วไปสำหรับ Python3 ที่คุณต้องการprint(b"Hello,\nworld!".decode('unicode_escape'))
ChristopheD

3
สำหรับ python 3 ให้ใช้value.encode('utf-8').decode('unicode_escape')
Casey Kuball

8
คำเตือน: value.encode('utf-8').decode('unicode_escape') ทำให้อักขระที่ไม่ใช่ ASCII ในสตริงเสียหาย เว้นแต่ว่าอินพุตได้รับการรับรองว่ามีเฉพาะอักขระ ASCII นี่ไม่ใช่วิธีแก้ปัญหาที่ถูกต้อง
Alex Peters

35

คุณสามารถใช้ast.literal_evalที่ปลอดภัย:

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

แบบนี้:

>>> import ast
>>> escaped_str = '"Hello,\\nworld!"'
>>> print ast.literal_eval(escaped_str)
Hello,
world!

3
การมีเครื่องหมายเอฟเอ็ม - โคลอนในสตริงจะทำลายโค้ดนี้ แสดงข้อผิดพลาดทางไวยากรณ์ "อักขระที่ไม่คาดคิดหลังจากอักขระต่อเนื่องบรรทัด"
darksky

3
@darksky สังเกตว่าastไลบรารีต้องการเครื่องหมายคำพูด (อย่างใดอย่างหนึ่ง"หรือ'แม้กระทั่ง"""หรือ''') รอบ Escape_str ของคุณเนื่องจากพยายามเรียกใช้เป็นรหัส Python แต่เพิ่มความปลอดภัย (ป้องกันการแทรกสตริง)
InQβ

@ no1xsyzy: ซึ่งในกรณีของ OP ก็เป็นอย่างนั้นอยู่แล้ว นี่คือคำตอบที่ถูกต้องเมื่อstrเป็นreprของstrหรือbytesวัตถุในกรณีของ OP; unicode-escapeคำตอบตัวแปลงสัญญาณสำหรับเมื่อมันไม่ได้เป็นreprแต่บางรูปแบบอื่นของข้อความหนี (ไม่ได้ล้อมรอบด้วยคำพูดที่เป็นส่วนหนึ่งของข้อมูลสตริงเอง)
ShadowRanger

ด้วยอักขระ utf-8 สิ่งนี้จะไม่ทำงาน ชำระเงินคำตอบสุดท้ายด้วยแพ็คเกจรหัส มันใช้งานได้จริง
rubmz

FWIW ฉันพยายามแยกวิเคราะห์ข้อความ JSON ที่หลบหนีและยังคงได้รับข้อผิดพลาด[ERROR] TypeError: string indices must be integersนี้และวิธีนี้ได้ผลเพื่อแก้ปัญหานั้น Unescape สตริงแล้วแยกวิเคราะห์เป็น JSON
พระไซเบอร์

20

คำตอบที่ได้รับทั้งหมดจะแตกในสตริง Unicode ทั่วไป ต่อไปนี้ใช้ได้กับ Python3 ในทุกกรณีเท่าที่ฉันสามารถบอกได้:

from codecs import encode, decode
sample = u'mon€y\\nröcks'
result = decode(encode(sample, 'latin-1', 'backslashreplace'), 'unicode-escape')
print(result)

ตามที่ระบุไว้ในความคิดเห็นคุณสามารถใช้literal_evalวิธีการจากastโมดูลดังนี้:

import ast
sample = u'mon€y\\nröcks'
print(ast.literal_eval(F'"{sample}"'))

หรือเช่นนี้เมื่อสายของคุณจริงๆมีตัวอักษรสตริง (รวมถึงคำพูด):

import ast
sample = u'"mon€y\\nröcks"'
print(ast.literal_eval(sample))

อย่างไรก็ตามหากคุณไม่แน่ใจว่าสตริงอินพุตใช้เครื่องหมายอัญประกาศคู่หรือเดี่ยวเป็นตัวคั่นหรือเมื่อคุณไม่สามารถสันนิษฐานได้ว่าเป็นค่า Escape อย่างถูกต้องทั้งหมดliteral_evalอาจเพิ่มขึ้นSyntaxErrorในขณะที่วิธีการเข้ารหัส / ถอดรหัสจะยังคงใช้งานได้


ast.literal_eval('"mon€y\\nröcks"') == "mon€y\nröcks"ใช้งานได้ดีสำหรับฉันกับ Python 3.7.3
oldrinb

ขอบคุณสำหรับความคิดเห็น @oldrinb! ฉันแก้ไขคำตอบเพื่อรวมสิ่งนั้น
Jesko Hüttenhain

14

ใน python 3 อstrอบเจ็กต์ไม่มีdecodeเมธอดและคุณต้องใช้bytesอ็อบเจกต์ คำตอบของ ChristopheD ครอบคลุม python 2

# create a `bytes` object from a `str`
my_str = "Hello,\\nworld"
# (pick an encoding suitable for your str, e.g. 'latin1')
my_bytes = my_str.encode("utf-8")

# or directly
my_bytes = b"Hello,\\nworld"

print(my_bytes.decode("unicode_escape"))
# "Hello,
# world"

2
รวมเข้าด้วยกัน, value.encode('utf-8').decode('unicode_escape').
Casey Kuball

6
สิ่งนี้จะพังหากสตริงมีอักขระ utf-8 ที่ไม่ใช่ ascii (เช่นอักขระโปแลนด์)
Pax0r

คุณได้ลองเลือกการเข้ารหัสที่เหมาะสมกับการขัดจังหวะในการโทรencodeหรือไม่?
asac

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