UnicodeDecodeError: ตัวแปลงสัญญาณ 'ascii' ไม่สามารถถอดรหัสไบต์ 0xd1 ในตำแหน่งที่ 2: ลำดับไม่อยู่ในช่วง (128)


107

ฉันกำลังพยายามทำงานกับชุดข้อมูลขนาดใหญ่ที่มีอักขระที่ไม่เป็นมาตรฐานอยู่ในนั้น ฉันจำเป็นต้องใช้ Unicode ตามข้อกำหนดของงาน แต่ฉันรู้สึกงุนงง (และค่อนข้างจะทำผิดทั้งหมด)

ฉันเปิด CSV โดยใช้:

 15     ncesReader = csv.reader(open('geocoded_output.csv', 'rb'), delimiter='\t', quotechar='"')

จากนั้นฉันพยายามเข้ารหัสด้วย:

name=school_name.encode('utf-8'), street=row[9].encode('utf-8'), city=row[10].encode('utf-8'), state=row[11].encode('utf-8'), zip5=row[12], zip4=row[13],county=row[25].encode('utf-8'), lat=row[22], lng=row[23])

ฉันกำลังเข้ารหัสทุกอย่างยกเว้น lat และ lng เพราะต้องส่งไปยัง API เมื่อฉันรันโปรแกรมเพื่อแยกวิเคราะห์ชุดข้อมูลเป็นสิ่งที่ฉันสามารถใช้ได้ฉันจะได้รับ Traceback ดังต่อไปนี้

Traceback (most recent call last):
  File "push_into_db.py", line 80, in <module>
    main()
  File "push_into_db.py", line 74, in main
    district_map = buildDistrictSchoolMap()
  File "push_into_db.py", line 32, in buildDistrictSchoolMap
    county=row[25].encode('utf-8'), lat=row[22], lng=row[23])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 in position 2: ordinal not in range(128)

ฉันคิดว่าฉันควรบอกคุณว่าฉันใช้ python 2.7.2 และนี่เป็นส่วนหนึ่งของแอพที่สร้างบน django 1.4 ฉันได้อ่านโพสต์ต่างๆเกี่ยวกับหัวข้อนี้ แต่ดูเหมือนจะไม่มีข้อใดเกี่ยวข้องโดยตรง ความช่วยเหลือใด ๆ จะได้รับการชื่นชมอย่างมาก

คุณอาจต้องการทราบด้วยว่าอักขระที่ไม่ได้มาตรฐานบางตัวที่ทำให้เกิดปัญหาคือÑและอาจเป็นไปได้ว่าÉ


1
การเข้ารหัสไฟล์ต้นฉบับของคุณคืออะไร? ฉันคิดว่าคุณควรถอดรหัสตามการเข้ารหัสดั้งเดิมแล้วแปลงเป็น utf 8
xiao 啸

การเข้ารหัสที่ซ้ำกันที่เป็นไปได้ทำให้ตัวแปลงสัญญาณ "'ascii' ไม่สามารถเข้ารหัสอักขระ ... ลำดับที่ไม่อยู่ในช่วง (128)" [Ed.: และอีกประมาณหนึ่งพันล้านคนฉันแน่ใจเช่นกัน]
Karl Knechtel

คำตอบ:


152

Unicode ไม่เท่ากับ UTF-8 หลังเป็นเพียงการเข้ารหัสสำหรับอดีต

คุณกำลังทำมันผิดวิธี คุณกำลังอ่าน UTF-8- เข้ารหัสข้อมูลเพื่อให้คุณได้ถอดรหัสสตริง UTF-8 เข้ารหัสเป็นสตริงยูนิโค้ด

ดังนั้นเพียงแค่แทนที่.encodeด้วย.decodeและควรใช้งานได้ (หาก. csv ของคุณเข้ารหัส UTF-8)

แม้ว่าจะไม่มีอะไรต้องละอายใจ ฉันพนันได้เลยว่าโปรแกรมเมอร์ 3 ใน 5 คนมีปัญหาในการทำความเข้าใจสิ่งนี้ในตอนแรกถ้าไม่มาก;)

อัปเดต: หากข้อมูลอินพุตของคุณไม่ได้เข้ารหัส UTF-8 คุณต้อง.decode()มีการเข้ารหัสที่เหมาะสมแน่นอน หากไม่มีอะไรให้ python จะถือว่า ASCII ซึ่งเห็นได้ชัดว่าล้มเหลวในอักขระที่ไม่ใช่ ASCII


1
สาเหตุของข้อผิดพลาดคือ Python พยายามถอดรหัสโดยอัตโนมัติจากการเข้ารหัสเริ่มต้น ASCII เพื่อให้สามารถเข้ารหัสตามที่เขาระบุเป็น UTF-8 เนื่องจากข้อมูลไม่ใช่ ASCII ที่ถูกต้องจึงใช้งานไม่ได้
agf

7
แน่นอน แต่ถ้าเป็นข้อมูลที่เข้ารหัส UTF8 (ตามที่ฉันเดา) .decode('utf-8')ควรทำเคล็ดลับหรือไม่?
ch3ka

แน่นอนว่าคุณคิดถูก ฉันแค่อธิบายว่าทำไมคุณถึงได้รับข้อผิดพลาดเฉพาะในสถานการณ์นี้
agf

1
สมบูรณ์แบบ! ขอบคุณมาก. ปรากฎว่ามันคือ. ถอดรหัส ('latin-1') - นี่ก็สมเหตุสมผลเพราะมันเป็นÑที่ทำให้ฉันมีปัญหา อีกแล้ว! ขอบคุณ!
jelkimantis

วิธีแก้ปัญหาของคุณใช้ได้กับบางกรณี แต่ในกรณีที่ฉันใช้สิ่งนี้ฉันได้รับข้อผิดพลาดตัวแปลงสัญญาณ 'ascii' อีกตัวไม่สามารถเข้ารหัสอักขระ u '\ xf1' ในตำแหน่งที่ 2: ลำดับไม่อยู่ในช่วง (128)
Vikash Mishra

84

เพียงเพิ่มบรรทัดนี้ในรหัสของคุณ:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

5
AttributeError: module 'sys' ไม่มีแอตทริบิวต์ 'setdefaultencoding' ดูเหมือนจะไม่ทำงานใน Python 3
skjerns

ว้าววว! สิ่งนี้ช่วยฉันได้
Shougo Makishima

1
ใช้งานได้กับ Python 2.7 ของฉันโปรดทราบว่าต้องโหลดซ้ำ (sys) มิฉะนั้น setdefaultencoding จะไม่สามารถเข้าถึงได้
Yu Shen

1
นั่นเป็นสิ่งเดียวที่ทำให้ฉันได้ผลจากคำถาม SO มากมาย ขอบคุณมาก!
Freedo

ไม่ได้กำหนดชื่อ 'โหลดซ้ำ'
Davide

28

สำหรับผู้ใช้ Python 3 คุณทำได้

with open(csv_name_here, 'r', encoding="utf-8") as f:
    #some codes

ใช้ได้กับกระติกน้ำด้วย :)


1
นี่เป็นครั้งแรกที่ฉันช่วยคนที่นี่ รู้สึกดีที่ได้ช่วย :)
Skrmnghrd

1
และคุณก็ช่วยฉันด้วย :) คำตอบอื่น ๆ ทั้งหมดใช้ไม่ได้สำหรับการอ่านไฟล์ ตอนนี้ฉันต้องหาวิธีแก้ไขด้วยสำหรับการเขียน;)
user2194898

คุณช่วยส่งลิงค์รหัสของคุณมาให้ฉันได้ไหม ฉันจะพยายามช่วย
Skrmnghrd

9

สาเหตุหลักของข้อผิดพลาดคือการเข้ารหัสเริ่มต้นที่ python สันนิษฐานคือ ASCII ดังนั้นหากข้อมูลสตริงที่จะเข้ารหัสencode('utf8')มีอักขระที่อยู่นอกช่วง ASCII เช่นสำหรับสตริงเช่น 'hgvcj 터파크 387' python จะส่งข้อผิดพลาดเนื่องจากสตริงไม่อยู่ในรูปแบบการเข้ารหัสที่คาดไว้

หากคุณใช้ python เวอร์ชันก่อนหน้าเวอร์ชัน 3.5 การแก้ไขที่เชื่อถือได้คือการตั้งค่าการเข้ารหัสเริ่มต้นที่ python สันนิษฐานเป็นutf8:

import sys
reload(sys)
sys.setdefaultencoding('utf8')
name = school_name.encode('utf8')

วิธีนี้ python จะสามารถคาดการณ์อักขระภายในสตริงที่อยู่นอกช่วง ASCII ได้

อย่างไรก็ตามหากคุณใช้ python เวอร์ชัน 3.5 ขึ้นไปฟังก์ชัน reload () จะไม่สามารถใช้งานได้ดังนั้นคุณจะต้องแก้ไขโดยใช้การถอดรหัสเช่น

name = school_name.decode('utf8').encode('utf8')

อะไรคือความแตกต่างระหว่างคำตอบของคุณกับของฉัน
khelili miliana

1
รายละเอียดเพิ่มเติม. ผู้คนมักพบว่ารายละเอียดเชิงสาเหตุเป็นประโยชน์ และรหัสของคุณใช้งานได้ btw ไม่มีเจตนาสร้างความเสื่อมเสีย
Temi Fakunle

1
สามารถโหลดซ้ำได้ใน Python 3 คุณเพียงแค่ต้องนำเข้า จากการรีโหลดการนำเข้า Imp
Meow

@Meow แต่ไม่มี sys.setdefaultencoding ใน Python 3 ดังนั้นในบริบทของความเข้ากันได้ py2 \ py3 การตรวจสอบบางอย่างจะทำ sys.getdefaultencoding () อาจจะ ขอขอบคุณคำแนะนำเกี่ยวกับเรื่องนั้น stackoverflow.com/questions/28127513/…
Konst54

2

สำหรับผู้ใช้ Python 3:

การเปลี่ยนการเข้ารหัสจาก 'ascii' เป็น 'latin1' ได้ผล

นอกจากนี้คุณสามารถลองค้นหาการเข้ารหัสโดยอัตโนมัติโดยอ่าน 10,000 ไบต์อันดับต้น ๆ โดยใช้ข้อมูลโค้ดด้านล่าง:

import chardet  
with open("dataset_path", 'rb') as rawdata:  
            result = chardet.detect(rawdata.read(10000))  
print(result)

2

คอมพิวเตอร์ของฉันตั้งค่าภาษาผิด

ฉันทำครั้งแรก

>>> import locale
>>> locale.getpreferredencoding(False)
'ANSI_X3.4-1968'

locale.getpreferredencoding(False)เป็นฟังก์ชั่นที่เรียกว่าโดยเมื่อคุณไม่ได้ให้การเข้ารหัสopen() เอาท์พุทควรจะเป็น'UTF-8'แต่ในกรณีนี้มันเป็นบางอย่างที่แตกต่างจาก ASCII

จากนั้นฉันรันคำสั่ง bash localeและได้ผลลัพธ์นี้

$ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

ดังนั้นฉันจึงใช้ตำแหน่งที่ตั้งของ Ubuntu เริ่มต้นซึ่งทำให้ Python เปิดไฟล์เป็น ASCII แทนที่จะเป็น UTF-8 ฉันต้องตั้งค่าภาษาของฉันเป็นen_US.UTF-8

sudo apt install locales 
sudo locale-gen en_US en_US.UTF-8    
sudo dpkg-reconfigure locales

หากคุณไม่สามารถเปลี่ยนระบบโลแคลได้คุณสามารถเรียกใช้โค้ด Python ทั้งหมดของคุณได้ดังนี้:

PYTHONIOENCODING="UTF-8" python3 ./path/to/your/script.py

หรือทำ

export PYTHONIOENCODING="UTF-8"

เพื่อตั้งค่าในเชลล์ที่คุณเรียกใช้


1

หากคุณพบปัญหานี้ขณะใช้งาน certbot ขณะสร้างหรือต่ออายุใบรับรองโปรดใช้วิธีการต่อไปนี้

grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

คำสั่งนั้นพบอักขระที่กระทำผิด "´" ในไฟล์. config หนึ่งไฟล์ในความคิดเห็น หลังจากลบออก (คุณสามารถแก้ไขความคิดเห็นได้ตามต้องการ) และโหลด nginx ใหม่ทุกอย่างก็ทำงานอีกครั้ง

ที่มา: https://github.com/certbot/certbot/issues/5236


0

หรือเมื่อคุณจัดการกับข้อความใน Python หากเป็นข้อความ Unicode ให้จดบันทึกว่าเป็น Unicode

ตั้งแทนเพียงtext=u'unicode text'text='unicode text'

สิ่งนี้ใช้ได้ผลในกรณีของฉัน



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