ความแตกต่างระหว่างการเข้ารหัส / ถอดรหัสคืออะไร?


180

ฉันไม่เคยแน่ใจว่าฉันเข้าใจความแตกต่างระหว่าง str / unicode decode และ encode

ฉันรู้ว่าstr().decode()สำหรับเมื่อคุณมีสตริงของไบต์ที่คุณรู้ว่ามีการเข้ารหัสตัวอักษรบางอย่างเนื่องจากชื่อการเข้ารหัสนั้นจะส่งกลับสตริง Unicode

ฉันรู้ว่าunicode().encode()แปลงอักขระ Unicode เป็นสตริงไบต์ตามชื่อการเข้ารหัสที่กำหนด

แต่ฉันไม่เข้าใจว่าอะไรstr().encode()และunicode().decode()มีไว้เพื่ออะไร มีใครอธิบายได้บ้างและอาจแก้ไขสิ่งอื่นที่ฉันผิดไปได้ด้วย?

แก้ไข:

หลายคำตอบให้ข้อมูลเกี่ยวกับสิ่งที่.encodeไม่เกี่ยวกับสตริง แต่ไม่มีใครดูเหมือนจะรู้ว่าสิ่งที่.decodeไม่สำหรับ Unicode


ฉันคิดว่าคำตอบที่สองของหน้านี้ชัดเจนและรัดกุม
Ben

คำตอบ:


106

decodeวิธีการของสตริง Unicode จริงๆไม่ได้มีการใช้งานใด ๆ ที่ทั้งหมด (ยกเว้นกรณีที่คุณมีข้อมูลที่ไม่ใช่ข้อความบางอย่างในสายอักขระ Unicode ด้วยเหตุผลบางอย่าง - ดูด้านล่าง) ฉันคิดว่ามันเป็นเพราะเหตุผลทางประวัติศาสตร์เป็นหลัก ใน Python 3 มันหายไปหมดแล้ว

unicode().decode()จะทำการเข้ารหัสโดยปริยายของการsใช้ตัวแปลงสัญญาณเริ่มต้น (ascii) ตรวจสอบเช่นนี้:

>>> s = u'ö'
>>> s.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

>>> s.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

ข้อความแสดงข้อผิดพลาดเหมือนกันทุกประการ

สำหรับstr().encode()มันเป็นวิธีอื่น ๆ - มันพยายามนัยถอดรหัสของsกับการเข้ารหัสเริ่มต้น:

>>> s = 'ö'
>>> s.decode('utf-8')
u'\xf6'
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

ใช้แบบนี้str().encode()ก็ยังฟุ่มเฟือย

แต่มีแอปพลิเคชันอื่น ๆ ของวิธีการหลังที่มีประโยชน์: มีการเข้ารหัสที่ไม่มีส่วนเกี่ยวข้องกับชุดอักขระและสามารถใช้กับสตริง 8 บิตในวิธีที่มีความหมาย:

>>> s.encode('zip')
'x\x9c;\xbc\r\x00\x02>\x01z'

แม้ว่าคุณจะถูกต้อง: การใช้ "การเข้ารหัส" ที่คลุมเครือสำหรับทั้งสองแอปพลิเคชันเหล่านี้คือ ... น่าแปลกใจ อีกครั้งด้วยการแยกbyteและstringประเภทใน Python 3 นี่ไม่ใช่ปัญหาอีกต่อไป


4
.decode()บนสตริง Unicode อาจมีประโยชน์เช่นprint u'\\u0203'.decode('unicode-escape')
jfs

ตัวอย่างที่ดี @JFSebastian ใน python3 ฉันเดาว่าคุณน่าจะ:print u'\\u0203'.encode('utf8').decode('unicode-escape')
AJP

1
@AJP: บน Python 3:codecs.decode(u'\\u0203', 'unicode-escape')
jfs

@hop: ใช่ ในการตรวจสอบอินพุตที่ไม่ถูกต้องและสำหรับความเข้ากันได้ของ Python 2/3 สตริงสามารถเข้ารหัสได้อย่างชัดเจนโดยใช้การasciiเข้ารหัส:\\u0203\u00e4'.encode('ascii').decode('unicode-escape')
jfs

@hop: ความคิดเห็นแรกของคุณ (ทำไมคุณถึงลบมันออกไปอย่าลบความคิดเห็นที่ตอบกลับแล้ว) พูดไปแล้ว ตอบกลับของฉัน ( .encode('ascii').decode('unicode-escape')) sys.getdefaultencoding()ไม่ได้ขึ้นอยู่กับ
jfs

71

เพื่อเป็นตัวแทนของสายอักขระ Unicode เป็นสตริงของไบต์เป็นที่รู้จักกันเข้ารหัส u'...'.encode(encoding)ใช้

ตัวอย่าง:

    >>> u'æøå'.encode ('utf8')
    '\ xc3 \ X83 \ xC2 \ xa6 \ xc3 \ X83 \ xC2 \ xb8 \ xc3 \ X83 \ xC2 \ xa5'
    >>> u'æøå'.encode ('latin1')
    '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'
    >>> u'æøå'.encode ('ascii')
    UnicodeEncodeError: ตัวแปลงสัญญาณ 'ascii' ไม่สามารถเข้ารหัสอักขระในตำแหน่ง 0-5: 
    ลำดับไม่อยู่ในช่วง (128)

โดยทั่วไปคุณเข้ารหัสสตริง Unicode เมื่อใดก็ตามที่คุณต้องการใช้สำหรับ IO เช่นถ่ายโอนผ่านเครือข่ายหรือบันทึกลงดิสก์ไฟล์

การแปลงสตริงของไบต์สตริง Unicode เป็นที่รู้จักกันเป็นถอดรหัส ใช้unicode('...', encoding)หรือ '... '. ถอดรหัส (เข้ารหัส)

ตัวอย่าง:

   >>> u'æøå '
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5' # ล่ามจะพิมพ์วัตถุ Unicode อย่างนั้น
   >>> ยูนิโคด ('\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5', 'latin1')
   U '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'
   >>> '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'.decode (' latin1 ')
   U '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'

โดยทั่วไปคุณจะถอดรหัสสตริงไบต์ทุกครั้งที่คุณรับข้อมูลสตริงจากเครือข่ายหรือจากไฟล์ดิสก์

ฉันเชื่อว่ามีการเปลี่ยนแปลงบางอย่างในการจัดการ Unicode ในหลาม 3 ดังนั้นข้างต้นอาจไม่ถูกต้องสำหรับหลาม 3

บางลิงค์ที่ดี:


6
คุณไม่ได้ตอบคำถามของ OP OP ต้องการทราบว่า str.encode () และ unicode.decode () ทำอะไร คุณเพิ่งทำซ้ำสิ่งที่ระบุไว้ในคำถามเดิม
stuckintheshuck

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

คำตอบที่ยอดเยี่ยม! สิ่งนี้ควรขึ้นไป !!
sandyp

16

anUnicode encode ('เข้ารหัส') ส่งผลให้วัตถุสตริงและสามารถเรียกบนวัตถุ Unicode

สตริง. ถอดรหัส ('การเข้ารหัส') ส่งผลให้วัตถุUnicodeและสามารถเรียกบนสตริงที่เข้ารหัสในการเข้ารหัสที่กำหนด


คำอธิบายเพิ่มเติมบางส่วน:

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

แต่มีเวลามาเมื่อคุณต้องการพิมพ์วัตถุ Unicode ของคุณเพื่อคอนโซลหรือลงในไฟล์ข้อความบางอย่าง ดังนั้นคุณต้องเข้ารหัสมัน (เช่น - ใน UTF-8) คุณเรียก encode ('utf-8') และคุณได้รับสตริงที่มี '\ u <someNumber> ด้านในซึ่งสามารถพิมพ์ได้อย่างสมบูรณ์

จากนั้นอีกครั้ง - คุณต้องการทำสิ่งที่ตรงกันข้าม - อ่านสตริงที่เข้ารหัสใน UTF-8 และถือว่าเป็น Unicode ดังนั้น \ u360 จะเป็นอักขระหนึ่งตัวไม่ใช่ 5 จากนั้นคุณถอดรหัสสตริง (ด้วยการเข้ารหัสที่เลือก) และ รับวัตถุใหม่เอี่ยมของ unicode

คุณสามารถเลือกการเข้ารหัสในทางที่ผิดเช่น 'zip', 'base64', 'rot' และบางส่วนจะแปลงจากสตริงเป็นสตริง แต่ฉันเชื่อว่ากรณีที่พบบ่อยที่สุดคือ UTF-8 / UTF-16 และสตริง


12

mybytestring.encode (somecodec) มีความหมายสำหรับค่าเหล่านี้ของsomecodec:

  • base64
  • bz2
  • zlib
  • แม่มด
  • quopri
  • ROT13
  • string_escape
  • UU

ฉันไม่แน่ใจว่าการถอดรหัสข้อความ unicode ที่ถอดรหัสแล้วนั้นดีสำหรับ การลองด้วยการเข้ารหัสดูเหมือนว่าจะพยายามเข้ารหัสด้วยการเข้ารหัสเริ่มต้นของระบบก่อนเสมอ


5

มีการเข้ารหัสสองสามข้อที่สามารถใช้เพื่อกำจัด / เข้ารหัสจาก str ไปยัง str หรือจาก unicode เป็น unicode ตัวอย่างเช่น base64, hex หรือ rot13 พวกเขามีการระบุไว้ในโมดูลแปลงสัญญาณ

แก้ไข:

ข้อความถอดรหัสบนสตริง Unicode สามารถเลิกทำการดำเนินการเข้ารหัสที่สอดคล้องกัน:

In [1]: u'0a'.decode('hex')
Out[1]: '\n'

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


1
-1: วิธีถอดรหัสไม่ได้ถูกนำไปใช้กับวัตถุ Unicode แต่วัตถุ Unicode จะถูกเข้ารหัสเป็น bytestring 'ascii' แทนก่อนที่การดำเนินการถอดรหัสจะเริ่มขึ้น สำหรับหลักฐานการยืนยันนั้นลองใช้u'ã'.decode ('hex') - ซึ่งให้ผล UnicodeEncodeError
nosklo

2
@nosklo: ถูกต้อง สิ่งที่ฉันหมายถึงจริงๆก็คือวัตถุ Unicode มีวิธีการถอดรหัส () เพื่อให้คุณสามารถใช้ตัวแปลงสัญญาณที่ไม่ได้ใช้อักขระกับตัวแปลงสัญญาณได้เช่นกัน การเข้ารหัสที่ไม่ใช่ตัวละครทั้งหมดนี้ทำให้ส่วนต่อประสานนี้ยุ่งเหยิงใน Python <3

1

คำตอบง่ายๆคือพวกมันตรงข้ามกัน

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

ตัวอย่างเช่น '\ xe4 \ xb8 \ xad \ xe6 \ x96 \ x87' เป็นตัวแทนของตัวอักษรจีนสองตัว แต่คอมพิวเตอร์เท่านั้นที่รู้ (หมายถึงพิมพ์หรือเก็บ) มันเป็นตัวอักษรจีนเมื่อพวกเขาได้รับพจนานุกรมเพื่อค้นหาสิ่งนั้น คำภาษาจีนในกรณีนี้มันเป็นพจนานุกรม "utf-8" และมันจะล้มเหลวในการแสดงคำภาษาจีนที่ตั้งใจถ้าคุณดูในพจนานุกรมอื่นหรือผิด (ใช้วิธีถอดรหัสที่แตกต่างกัน)

decode()ในกรณีดังกล่าวข้างต้นกระบวนการสำหรับคอมพิวเตอร์ที่จะมองหาคำภาษาจีนคือ

encode()และขั้นตอนของคอมพิวเตอร์การเขียนภาษาจีนในหน่วยความจำคอมพิวเตอร์

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

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