วิธีแก้ไข:“ UnicodeDecodeError: 'ascii' codec ไม่สามารถถอดรหัสไบต์ได้”


459
as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

จะแก้ไขได้อย่างไร?

ในแอพพลิเคชั่นบล็อกสแตติกที่ใช้ python อื่น ๆ โพสต์ภาษาจีนสามารถเผยแพร่ได้สำเร็จ เช่น app นี้: http://github.com/vrypan/bucket3 ในเว็บไซต์ของฉันhttp://bc3.brite.biz/โพสต์ภาษาจีนสามารถเผยแพร่ได้สำเร็จ


คำตอบ:


569

tl; dr / การแก้ไขด่วน

  • อย่าถอดรหัส / เข้ารหัสโดยเจตนา
  • อย่าถือว่าสตริงของคุณเข้ารหัส UTF-8
  • ลองแปลงสตริงเป็นสตริง Unicode โดยเร็วที่สุดในรหัสของคุณ
  • แก้ไขสถานที่ของคุณ: วิธีแก้ UnicodeDecodeError ใน Python 3.6?
  • อย่าถูกล่อลวงให้ใช้reloadแฮ็คด่วน

Unicode Zen ใน Python 2.x - รุ่นยาว

การไม่เห็นแหล่งที่มาเป็นการยากที่จะทราบสาเหตุที่แท้จริงดังนั้นฉันจะต้องพูดโดยทั่วไป

UnicodeDecodeError: 'ascii' codec can't decode byteโดยทั่วไปจะเกิดขึ้นเมื่อคุณพยายามแปลง Python 2.x strที่มีไม่ใช่ ASCII เป็นสตริง Unicode โดยไม่ต้องระบุการเข้ารหัสของสตริงต้นฉบับ

โดยสังเขปสตริง Unicode เป็นสตริง Python ที่แยกจากกันอย่างสิ้นเชิงซึ่งไม่มีการเข้ารหัสใด ๆ พวกเขาเก็บรหัสจุด Unicode เท่านั้นดังนั้นจึงสามารถเก็บจุด Unicode ใด ๆ ได้จากทั่วทั้งสเปกตรัม Strings มีข้อความที่เข้ารหัสเลนซา UTF-8, UTF-16, ISO-8895-1, GBK, Big5 ฯลฯสตริงจะถูกถอดรหัสเป็น UnicodeและUnicodes จะถูกเข้ารหัสสตริง ไฟล์และข้อมูลข้อความจะถูกถ่ายโอนในสตริงที่เข้ารหัสเสมอ

ผู้เขียนโมดูล Markdown อาจใช้unicode()(โดยมีข้อยกเว้นเกิดขึ้น) เป็นเกตคุณภาพไปยังโค้ดที่เหลือ - มันจะแปลง ASCII หรือห่อสตริง Unicode ที่มีอยู่แล้วเป็นสตริง Unicode ใหม่ ผู้เขียน Markdown ไม่สามารถรู้การเข้ารหัสของสตริงที่เข้ามาดังนั้นจะพึ่งพาคุณในการถอดรหัสสตริงเป็นสตริง Unicode ก่อนที่จะส่งไปยัง Markdown

สตริง Unicode สามารถประกาศในรหัสของคุณโดยใช้uคำนำหน้าเพื่อสตริง เช่น

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

สตริง Unicode อาจมาจากไฟล์ฐานข้อมูลและโมดูลเครือข่าย เมื่อสิ่งนี้เกิดขึ้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับการเข้ารหัส

gotchas

การแปลงจากstrเป็น Unicode unicode()สามารถเกิดขึ้นได้แม้ในขณะที่คุณไม่ชัดเจนโทร

สถานการณ์สมมติต่อไปนี้ทำให้เกิดUnicodeDecodeErrorข้อยกเว้น:

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'         

ตัวอย่าง

ในแผนภาพต่อไปนี้คุณสามารถดูวิธีcaféการเข้ารหัสในการเข้ารหัส "UTF-8" หรือ "Cp1252" ขึ้นอยู่กับประเภทของเทอร์มินัล ในทั้งสองตัวอย่างcafเป็นเพียง ascii ปกติ ใน UTF-8 éถูกเข้ารหัสโดยใช้สองไบต์ ใน "Cp1252" éคือ 0xE9 (ซึ่งเกิดขึ้นกับค่าจุด Unicode ด้วย (ไม่ใช่เรื่องบังเอิญ)) ความถูกต้องถูกdecode()เรียกใช้และการแปลงเป็น Python Unicode นั้นสำเร็จแล้ว: ไดอะแกรมของสตริงที่ถูกแปลงเป็นสตริง Python Unicode

ในแผนภาพนี้decode()ถูกเรียกด้วยascii(ซึ่งเหมือนกับการโทรunicode()โดยไม่ต้องเข้ารหัส) เนื่องจาก ASCII ไม่สามารถมีจำนวนไบต์ที่มากกว่า0x7Fนี้จะทำให้เกิดUnicodeDecodeErrorข้อยกเว้น:

ไดอะแกรมของสตริงที่ถูกแปลงเป็นสตริง Python Unicode ที่มีการเข้ารหัสผิด

แซนด์วิช Unicode

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

อินพุต / ถอดรหัส

รหัสแหล่งที่มา

หากคุณต้องการที่จะอบไม่ใช่ ASCII เป็นรหัสที่มาของคุณเพียงแค่สร้างสตริง Unicode โดย prefixing uสตริงที่มี เช่น

u'Zürich'

ในการอนุญาตให้ Python ถอดรหัสซอร์สโค้ดของคุณคุณจะต้องเพิ่มส่วนหัวการเข้ารหัสเพื่อให้ตรงกับการเข้ารหัสไฟล์ของคุณ ตัวอย่างเช่นหากไฟล์ของคุณถูกเข้ารหัสเป็น 'UTF-8' คุณจะใช้:

# encoding: utf-8

นี้เป็นสิ่งจำเป็นเฉพาะเมื่อคุณมีไม่ใช่ ASCII ของคุณในรหัสที่มา

ไฟล์

โดยปกติจะได้รับข้อมูลที่ไม่ใช่ ASCII จากไฟล์ ioโมดูลให้ TextWrapper encodingที่ถอดรหัสไฟล์ของคุณได้ทันทีโดยใช้ที่กำหนด คุณต้องใช้การเข้ารหัสที่ถูกต้องสำหรับไฟล์ - ไม่สามารถเดาได้ง่าย ตัวอย่างเช่นสำหรับไฟล์ UTF-8:

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
     my_unicode_string = my_file.read() 

my_unicode_stringจะเหมาะสำหรับการส่งผ่านไปยัง Markdown หาก a UnicodeDecodeErrorจากread()บรรทัดแสดงว่าคุณอาจใช้ค่าการเข้ารหัสผิด

ไฟล์ CSV

โมดูล Python 2.7 CSV ไม่สนับสนุนอักขระที่ไม่ใช่ ASCII 😩 ความช่วยเหลือที่อยู่ในมืออย่างไรกับhttps://pypi.python.org/pypi/backports.csv

ใช้เหมือนข้างบน แต่ส่งไฟล์ที่เปิดไป:

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
    for row in csv.reader(my_file):
        yield row

ฐานข้อมูล

ไดรเวอร์ฐานข้อมูล Python ส่วนใหญ่สามารถส่งคืนข้อมูลใน Unicode แต่โดยปกติจะต้องมีการกำหนดค่าเล็กน้อย ใช้สตริง Unicode สำหรับแบบสอบถาม SQL เสมอ

MySQL

ในสตริงการเชื่อมต่อเพิ่ม:

charset='utf8',
use_unicode=True

เช่น

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
PostgreSQL

เพิ่ม:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

หน้าเว็บสามารถเข้ารหัสในการเข้ารหัสใด ๆ Content-typeหัวควรมีcharsetข้อมูลแบะท่าเข้ารหัส เนื้อหาสามารถถอดรหัสด้วยตนเองเทียบกับค่านี้ อีกวิธีหนึ่งคืองูหลามร้องขอresponse.textผลตอบแทนใน Unicodes

ด้วยมือ

หากคุณต้องถอดรหัสสตริงด้วยตนเองคุณสามารถทำได้my_string.decode(encoding)โดยencodingการเข้ารหัสที่เหมาะสม งูหลาม 2.x สนับสนุนตัวแปลงสัญญาณที่จะได้รับที่นี่: มาตรฐานการเข้ารหัส อีกครั้งถ้าคุณได้UnicodeDecodeErrorแล้วคุณอาจมีการเข้ารหัสผิด

เนื้อของแซนวิช

ทำงานกับ Unicodes ได้เหมือนปกติ

เอาท์พุต

stdout / การพิมพ์

printเขียนผ่านสตรีม stdout Python พยายามกำหนดค่าตัวเข้ารหัสบน stdout เพื่อให้ Unicodes ถูกเข้ารหัสเป็นการเข้ารหัสของคอนโซล ตัวอย่างเช่นถ้าลินุกซ์ของเปลือกlocaleมีเอาท์พุทจะถูกเข้ารหัสเพื่อen_GB.UTF-8 UTF-8บน Windows คุณจะถูก จำกัด ที่หน้ารหัส 8 บิต

คอนโซลที่กำหนดค่าไม่ถูกต้องเช่นภาษาที่เสียหายสามารถนำไปสู่ข้อผิดพลาดการพิมพ์ที่ไม่คาดคิด PYTHONIOENCODINGตัวแปรสภาพแวดล้อมสามารถบังคับให้เข้ารหัสสำหรับ stdout

ไฟล์

เช่นเดียวกับอินพุตio.openสามารถใช้ในการแปลง Unicode เป็นสตริงไบต์ที่เข้ารหัส

ฐานข้อมูล

การกำหนดค่าเดียวกันสำหรับการอ่านจะช่วยให้ Unicodes สามารถเขียนได้โดยตรง

Python 3

Python 3 ไม่สามารถใช้ Unicode ได้มากกว่า Python 2.x อย่างไรก็ตามมันค่อนข้างสับสนน้อยกว่าในหัวข้อ เช่นปกติstrในขณะนี้คือสตริง Unicode และเก่าอยู่ในขณะนี้strbytes

การเข้ารหัสเริ่มต้นคือ UTF-8 ดังนั้นหากคุณ.decode()เป็นสตริงไบต์โดยไม่มีการเข้ารหัส Python 3 ใช้การเข้ารหัส UTF-8 สิ่งนี้อาจแก้ไขปัญหา Unicode ของผู้คนได้ 50%

ยิ่งไปกว่านั้นopen()ทำงานในโหมดข้อความตามค่าเริ่มต้นดังนั้นจะส่งกลับค่าถอดรหัสstr(Unicode) การเข้ารหัสมาจากภาษาของคุณซึ่งมีแนวโน้มที่จะเป็น UTF-8 ในระบบ Un * x หรือหน้ารหัส 8 บิตเช่น windows-1251 บนกล่อง Windows

ทำไมคุณไม่ควรใช้ sys.setdefaultencoding('utf8')

เป็นแฮ็คที่น่ารังเกียจ (มีเหตุผลที่คุณต้องใช้reload) ซึ่งจะปกปิดปัญหาและขัดขวางการย้ายไปยัง Python 3.x ทำความเข้าใจกับปัญหาแก้ไขสาเหตุที่แท้จริงและเพลิดเพลินกับ Unicode Zen ดูทำไมเราไม่ควรใช้ sys.setdefaultencoding ("utf-8") ในสคริปต์ py? สำหรับรายละเอียดเพิ่มเติม


2
สำหรับคนที่กำลังมองหาคำตอบของ Python 2 TLDR ที่มีประโยชน์มากขึ้น: ใช้io.openสำหรับการอ่าน / เขียนไฟล์ใช้from __future__ import unicode_literalsกำหนดค่าอินพุต / เอาต์พุตข้อมูลอื่น ๆ (เช่นฐานข้อมูล) เพื่อใช้ unicode
idbrii

แล้วเราจะแก้ไขได้อย่างไร ฮ่า ๆ นี่ไม่ใช่ปัญหาจากการเขียนสคริปต์ แต่มาจากการติดตั้ง
Matthew

@ Matthew PYTHONIOENCODING=utf-8ลองตั้งค่า หากไม่สามารถแก้ไขได้คุณจะต้องติดต่อผู้เขียนสคริปต์เพื่อแก้ไขรหัส
Alastair McCormack

498

ในที่สุดฉันก็รับมัน:

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

ขอตรวจสอบดูก่อน:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec  6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

utf8แสดงให้เห็นข้างต้นเข้ารหัสเริ่มต้นของงูหลามเป็น จากนั้นข้อผิดพลาดจะไม่มีอีกต่อไป


7
ฉันลองสิ่งนี้ แต่มันไม่สามารถเปลี่ยนการเข้ารหัสได้อย่างถาวร เมื่อออกจากคอนโซล python แล้วเริ่มใหม่อีกครั้งการเข้ารหัสยังคงเดิม
macemers

37
ขอบคุณ! แต่ทำไมเราต้องโหลด sys ใหม่หลังจากนำเข้า
Dmiters

6
@DmitryNarkevich เนื่องจากฟังก์ชั่นsetdefaultencodingของIllusive มันจะถูกลบเมื่อเริ่มต้น Python เนื่องจากไม่ควรเป็นส่วนหนึ่งของการวางจำหน่ายที่เหมาะสมตั้งแต่แรก
predi

3
หมายความว่าคุณยังไม่ได้แก้ไขสาเหตุที่แท้จริง คุณเพิ่งได้รับการแก้ไขในเรื่องการแปลงโดยนัยใด ๆ
Alastair McCormack

5
@miraculixx การเข้ารหัสเริ่มต้นของ Python 3 คือ UTF-8 ที่มีสตริง Unicode เป็นค่าเริ่มต้นstrดังนั้นจึงไม่เกินกำหนด ใน Python 2.x Unicode อยู่ในช่วงการเปลี่ยนภาพดังนั้นอาจเป็นอันตรายได้หากมีการเข้ารหัสเมื่อแปลงไบต์เป็น Unicode ดังนั้นการเข้ารหัสเริ่มต้น Py2 ของ ASCII sysเป็นตัวเลือกโดยเจตนาและเหตุผลที่เปลี่ยนการเข้ารหัสเริ่มต้นต้องสับเจตนาของโหลด วิธีที่ถูกต้องในการกำจัดข้อผิดพลาดในการเข้ารหัสใน Py2 คือการถอดรหัสและเข้ารหัสสตริง (ไบต์) อย่างไม่น่าสงสัยกับ Unicode เมื่อแปลงเป็นสิ่งที่จำเป็น - ไม่ใช่แค่สันนิษฐานว่าเป็นสตริงที่เข้ารหัส UTF-8
Alastair McCormack

130

นี่คือ "unicode issue" แบบคลาสสิค ฉันเชื่อว่าการอธิบายนี้เกินขอบเขตของคำตอบ StackOverflow เพื่ออธิบายสิ่งที่เกิดขึ้นอย่างสมบูรณ์

มันเป็นเรื่องที่อธิบายได้ดีที่นี่

โดยสรุปสั้น ๆ คุณได้ผ่านสิ่งที่ถูกตีความว่าเป็นสตริงไบต์ไปยังบางสิ่งที่จำเป็นต้องถอดรหัสเป็นอักขระ Unicode แต่ตัวแปลงสัญญาณเริ่มต้น (ascii) ล้มเหลว

งานนำเสนอที่ฉันแนะนำให้คุณให้คำแนะนำเพื่อหลีกเลี่ยงปัญหานี้ ทำรหัสของคุณให้เป็น "unicode Sandwich" ใน Python 2 การใช้ตัวfrom __future__ import unicode_literalsช่วย

อัปเดต: จะแก้ไขรหัสได้อย่างไร:

ตกลง - ในตัวแปร "แหล่งที่มา" ของคุณคุณมีบางไบต์ ยังไม่ชัดเจนจากคำถามของคุณว่าพวกเขาได้รับใน - คุณอาจอ่านจากเว็บฟอร์ม? ไม่ว่าในกรณีใดพวกเขาจะไม่ถูกเข้ารหัสด้วย ascii แต่ไพ ธ อนพยายามแปลงให้เป็นยูนิโค้ดโดยสมมติว่าเป็น คุณต้องบอกอย่างชัดเจนว่าการเข้ารหัสคืออะไร นี่หมายความว่าคุณต้องรู้ว่าการเข้ารหัสคืออะไร! นั่นไม่ใช่เรื่องง่ายเสมอไปและขึ้นอยู่กับว่าสายนี้มาจากไหน คุณสามารถทดสอบกับการเข้ารหัสทั่วไปบางอย่าง - เช่น UTF-8 คุณบอก unicode () การเข้ารหัสเป็นพารามิเตอร์ตัวที่สอง:

source = unicode(source, 'utf-8')

1
มันยังคงเป็นเรื่องปวดหัวนาย GreenAsJade คุณช่วยแก้ปัญหาที่เป็นรูปธรรมได้มั้ย
ชาวประมง

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

2
mr greenasjade: ฉันควรใส่ "source = unicode (source, 'utf-8') ที่ไหน?
ชาวประมง

7
แปลก ... หลังจากได้รับการตอบรับเชิงบวกมานานกว่าหนึ่งปีก็มีคะแนนลบสองเท่า ... หืม?
GreenAsJade

11
ใช้งานcurrentFile = open(filename, 'rt', encoding='latin1')หรือcurrentFile = open(filename, 'rt', encoding='utf-8')- ดูที่นี่: stackoverflow.com/a/23917799/2047442
irudyak

42

ในบางกรณีเมื่อคุณตรวจสอบการเข้ารหัสเริ่มต้นของคุณ ( print sys.getdefaultencoding()) จะส่งคืนว่าคุณกำลังใช้ ASCII หากคุณเปลี่ยนเป็น UTF-8 มันไม่ทำงานขึ้นอยู่กับเนื้อหาของตัวแปรของคุณ ฉันพบวิธีอื่น:

import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')

โดย, มันใช้งานได้กับปัญหาของฉันเมื่อใช้ python ในการโยน UnicodeDecodeError บน var = u "" "แปรเปลี่ยนสตริงขนาดใหญ่" ""
2426679

AttributeError: โมดูล 'sys' ไม่มีแอตทริบิวต์ 'setdefaultencoding'
Chaine

และreload(sys)ใช้สำหรับเหตุผลเฉพาะนั้น
Marcin Orlowski

1
ทำงานให้ฉัน! ขอบคุณ!
Maciej

22

ฉันกำลังค้นหาเพื่อแก้ไขข้อความแสดงข้อผิดพลาดต่อไปนี้:

unicodedecodeerror: 'ascii' codec ไม่สามารถถอดรหัสไบต์ 0xe2 ในตำแหน่ง 5454: ลำดับไม่อยู่ในช่วง (128)

ในที่สุดฉันก็ได้รับการแก้ไขโดยระบุ 'การเข้ารหัส':

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

หวังว่ามันจะช่วยคุณได้เช่นกัน


นี้แก้ไขข้อผิดพลาดสำหรับฉันเมื่ออ่าน / เขียนไฟล์. csv ไม่จำเป็นต้องมีสิ่งอื่น ๆ ที่ระบุไว้ในคำตอบอื่น ๆ
user5359531

ฉันไม่เข้าใจว่าทำไมคำตอบอื่น ๆ ให้รายละเอียดมาก ... แต่ลืมเกี่ยวกับวิธีแก้ปัญหาง่ายๆนี้ 10!
stan0

18
"UnicodeDecodeError: 'ascii' codec can't decode byte"

สาเหตุของข้อผิดพลาดนี้: input_string ต้องเป็นยูนิโค้ด แต่ได้รับ str

"TypeError: Decoding Unicode is not supported"

สาเหตุของข้อผิดพลาดนี้: พยายามแปลง unicode input_string เป็น Unicode


ดังนั้นก่อนตรวจสอบว่า input_string ของคุณคือ strและแปลงเป็น Unicode หากจำเป็น:

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

ประการที่สองข้างต้นเพียงแค่เปลี่ยนประเภท แต่ไม่ได้ลบตัวอักษรที่ไม่ใช่ ASCII หากคุณต้องการลบอักขระที่ไม่ใช่ ASCII:

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.

elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')

9

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

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

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

ตัวอย่าง:

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

นี่คือบางส่วนเพิ่มเติมให้เหตุผลเกี่ยวกับเรื่องนี้


สวัสดีใน Python 3 ฟังก์ชั่น _u มันไม่ได้ทำงานกับค่านี้ 'Ita £'
Martin

1
ตกลงว่าจะเริ่มจาก "การใช้เหตุผล" ของคุณที่ไหน? print unicode(u'Zürich', encoding="UTF-8")แล้วก็บ่นว่า "แต่น่าประหลาดใจที่คุณไม่สามารถเข้ารหัส Unicode ให้เป็น UTF8 ได้" unicode()ไม่เข้ารหัส มันถอดรหัสและคุณไม่สามารถถอดรหัส Unicode - มันถอดรหัสแล้ว!
Alastair McCormack

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

3
@miraculixx ฉันขอโทษฉันไม่ได้ตั้งใจที่จะเจอเรื่องกระตุก ความกังวลเกี่ยวกับการถอดรหัสและการเข้ารหัสทุกครั้งที่คุณใช้สตริงในรหัสของคุณนั้นไม่จำเป็น
Alastair McCormack

7

เพื่อแก้ไขปัญหานี้ในระดับระบบปฏิบัติการในการติดตั้ง Ubuntu ให้ตรวจสอบสิ่งต่อไปนี้:

$ locale charmap

ถ้าคุณได้รับ

locale: Cannot set LC_CTYPE to default locale: No such file or directory

แทน

UTF-8

จากนั้นตั้งค่าLC_CTYPEและLC_ALLเช่นนี้:

$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"

6

Encode แปลงวัตถุ Unicode ให้เป็นวัตถุสตริง ฉันคิดว่าคุณกำลังพยายามเข้ารหัสวัตถุสตริง ก่อนอื่นแปลงผลลัพธ์ของคุณให้เป็นวัตถุ Unicode แล้วเข้ารหัสวัตถุ Unicode เป็น 'utf-8' ตัวอย่างเช่น

    result = yourFunction()
    result.decode().encode('utf-8')

4

ฉันมีปัญหาเดียวกัน แต่ไม่ได้ผลสำหรับ Python 3 ฉันทำตามสิ่งนี้และแก้ไขปัญหาของฉันได้:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

คุณต้องตั้งค่าการเข้ารหัสเมื่อคุณกำลังอ่าน / เขียนไฟล์


4

มีข้อผิดพลาดเดียวกันและสิ่งนี้แก้ไขข้อผิดพลาดของฉัน ขอบคุณ! หลาม 2 และหลาม 3 แตกต่างกันในการจัดการยูนิโค้ดทำให้ไฟล์ดองค่อนข้างเข้ากันไม่ได้ในการโหลด ใช้อาร์กิวเมนต์การเข้ารหัสของ python ลิงค์ด้านล่างช่วยฉันแก้ปัญหาที่คล้ายกันเมื่อฉันพยายามเปิดข้อมูลที่ถูกดองจาก python 3.7 ของฉันในขณะที่ไฟล์ของฉันถูกบันทึกไว้ในเวอร์ชัน python 2.x https://blog.modest-destiny.com/posts/python-2-and-3-compatible-pickle-save-and-load/ ฉันคัดลอกฟังก์ชัน load_pickle ในสคริปต์ของฉันและเรียก load_pickle (pickle_file) ในขณะที่โหลด input_data เช่นนี้:

input_data = load_pickle("my_dataset.pkl")

ฟังก์ชัน load_pickle อยู่ที่นี่:

def load_pickle(pickle_file):
    try:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f)
    except UnicodeDecodeError as e:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f, encoding='latin1')
    except Exception as e:
        print('Unable to load data ', pickle_file, ':', e)
        raise
    return pickle_data

1
มันจะดีกว่าที่จะรวมคำจำกัดความของload_pickleฟังก์ชั่นในคำตอบของคุณ
sanyash


3

ในระยะสั้นเพื่อให้แน่ใจว่ามีการจัดการยูนิโค้ดที่เหมาะสมใน Python 2:

  • ใช้io.openสำหรับการอ่าน / เขียนไฟล์
  • ใช้ from __future__ import unicode_literals
  • กำหนดค่าอินพุต / เอาท์พุตข้อมูลอื่น ๆ (เช่นฐานข้อมูลเครือข่าย) ให้ใช้ Unicode
  • หากคุณไม่สามารถกำหนดค่าเอาต์พุตเป็น utf-8 ให้แปลงเอาต์พุตของคุณ print(text.encode('ascii', 'replace').decode())

สำหรับคำอธิบายดู @Alastair McCormack ของคำตอบรายละเอียด


•ใช้io.open(path, 'r', encoding='utf-8')เพื่ออ่านไฟล์ที่เข้ารหัส utf-8
Bob Stein

3

ฉันมีข้อผิดพลาดเดียวกันกับ URL ที่มีตัวอักษรที่ไม่ใช่ ASCII (ไบต์ที่มีค่า> 128) วิธีแก้ไขของฉัน:

url = url.decode('utf8').encode('utf-8')

หมายเหตุ: utf-8, utf8 เป็นเพียงนามแฝง การใช้เฉพาะ 'utf8' หรือ 'utf-8' ควรใช้วิธีเดียวกัน

ในกรณีของฉันทำงานให้ฉันใน Python 2.7 ฉันคิดว่าการมอบหมายนี้เปลี่ยน 'บางสิ่ง' ในการstrเป็นตัวแทนภายใน - นั่นคือมันบังคับให้ถอดรหัสอย่างถูกต้องของลำดับไบต์ที่สำรองในurlและในที่สุดก็ทำให้สตริงเป็นutf-8 strด้วย ความมหัศจรรย์ทั้งหมดในสถานที่ที่เหมาะสม Unicode ใน Python เป็นเวทย์มนตร์ดำสำหรับฉัน หวังว่ามีประโยชน์


1
เหตุใดจึงเป็นหนึ่งในนั้นและไม่ใช่คนอื่น
IgorGanapolsky

1
Python ยอมรับชื่อแทนสำหรับการเข้ารหัสชื่อฉันได้ลองแล้วและใช้ชื่อเดิม ... ฉันไม่ได้สังเกตว่าฉันเขียนมันต่างออกไปเพิ่มโน้ต
Fabiano Tarlao


1

ในโครงการ Django (1.9.10) / Python 2.7.5 ฉันมีโครงการบ่อย UnicodeDecodeErrorข้อยกเว้นส่วนใหญ่เมื่อฉันพยายามที่จะดึงสตริง Unicode ให้เข้าสู่ระบบ ฉันสร้างฟังก์ชันตัวช่วยสำหรับวัตถุที่ไม่มีกฎเกณฑ์เพื่อจัดรูปแบบโดยทั่วไปเป็นสตริง ASCII แบบ 8 บิตและแทนที่อักขระใด ๆ ที่ไม่อยู่ในตารางเป็น '?' ฉันคิดว่ามันไม่ใช่ทางออกที่ดีที่สุด แต่เนื่องจากการเข้ารหัสเริ่มต้นคือ ascii (และฉันไม่ต้องการเปลี่ยน) มันจะทำ:

def encode_for_logging (c, encoding = 'ascii'):
    ถ้า isinstance (c, basestring):
        return c.encode (การเข้ารหัส, 'แทนที่')
    elif isinstance (c, Iterable):
        c_ = []
        สำหรับ v ใน c:
            c_.append (encode_for_logging (v, การเข้ารหัส))
        ส่งคืน c_
    อื่น:
        return encode_for_logging (unicode (c))
`


1

ข้อผิดพลาดนี้เกิดขึ้นเมื่อมีอักขระที่ไม่ใช่ ASCII บางตัวในสายอักขระของเราและเรากำลังดำเนินการกับสายอักขระนั้นโดยไม่มีการถอดรหัสที่เหมาะสม สิ่งนี้ช่วยฉันแก้ปัญหาของฉัน ฉันกำลังอ่านไฟล์ CSV พร้อมด้วย ID คอลัมน์ข้อความและตัวถอดรหัสในไฟล์ด้านล่าง:

train_df = pd.read_csv("Example.csv")
train_data = train_df.values
for i in train_data:
    print("ID :" + i[0])
    text = i[1].decode("utf-8",errors="ignore").strip().lower()
    print("Text: " + text)

0

นี่คือทางออกของฉันเพียงเพิ่มการเข้ารหัส with open(file, encoding='utf8') as f

และเนื่องจากการอ่านไฟล์ถุงมือจะใช้เวลานานฉันจึงแนะนำให้ใช้ไฟล์ถุงมือเป็นไฟล์แบบอ้วน เมื่อเวลา netx ที่คุณอ่านน้ำหนักการฝังมันจะประหยัดเวลาของคุณ

import numpy as np
from tqdm import tqdm


def load_glove(file):
    """Loads GloVe vectors in numpy array.
    Args:
        file (str): a path to a glove file.
    Return:
        dict: a dict of numpy arrays.
    """
    embeddings_index = {}
    with open(file, encoding='utf8') as f:
        for i, line in tqdm(enumerate(f)):
            values = line.split()
            word = ''.join(values[:-300])
            coefs = np.asarray(values[-300:], dtype='float32')
            embeddings_index[word] = coefs

    return embeddings_index

# EMBEDDING_PATH = '../embedding_weights/glove.840B.300d.txt'
EMBEDDING_PATH = 'glove.840B.300d.txt'
embeddings = load_glove(EMBEDDING_PATH)

np.save('glove_embeddings.npy', embeddings) 

ลิงค์ส่วนสำคัญ: https://gist.github.com/BrambleXu/634a844cdd3cd04bb2e3ba3c83aef227


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