UnicodeDecodeError: codec 'ascii' không thể giải mã byte 0xd1 ở vị trí 2: thứ tự không trong phạm vi (128)


107

Tôi đang cố gắng làm việc với một tập dữ liệu rất lớn có một số ký tự không chuẩn trong đó. Tôi cần sử dụng unicode, theo thông số kỹ thuật công việc, nhưng tôi gặp khó khăn. (Và hoàn toàn có thể làm sai.)

Tôi mở CSV bằng:

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

Sau đó, tôi cố gắng mã hóa nó bằng:

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

Tôi đang mã hóa mọi thứ ngoại trừ lat và lng vì chúng cần được gửi tới một API. Khi tôi chạy chương trình để phân tích cú pháp tập dữ liệu thành những gì tôi có thể sử dụng, tôi nhận được Traceback sau.

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)

Tôi nghĩ rằng tôi nên nói với bạn rằng tôi đang sử dụng python 2.7.2 và đây là một phần của bản dựng ứng dụng trên django 1.4. Tôi đã đọc một số bài đăng về chủ đề này, nhưng không có bài nào trong số đó dường như áp dụng trực tiếp. Chúng tôi rất trân trọng bất kỳ sự giúp đỡ nào.

Bạn cũng có thể muốn biết rằng một số ký tự không chuẩn gây ra sự cố là Ñ và có thể là É.


1
Mã hóa tệp gốc của bạn là gì? Tôi nghĩ bạn nên giải mã nó theo mã hóa ban đầu và sau đó chuyển đổi thành utf 8
xiao 啸

Bản sao mã hóa có thể xảy ra khiến codec "'ascii' không thể mã hóa ký tự… thứ tự không nằm trong phạm vi (128)" [Ed .: và khoảng một triệu người khác, tôi chắc chắn.]
Karl Knechtel

Câu trả lời:


152

Unicode không bằng UTF-8. Cái sau chỉ là một bảng mã cho cái trước.

Bạn đang làm điều đó một cách sai lầm. Bạn đang đọc dữ liệu được mã hóa UTF-8 , vì vậy bạn phải giải mã Chuỗi được mã hóa UTF-8 thành một chuỗi unicode.

Vì vậy, chỉ cần thay thế .encodebằng .decodevà nó sẽ hoạt động (nếu .csv của bạn được mã hóa UTF-8).

Không có gì phải xấu hổ, mặc dù. Tôi cá rằng 3 trong 5 lập trình viên đã gặp khó khăn khi hiểu điều này lần đầu tiên, nếu không muốn nói là nhiều hơn;)

Cập nhật: Nếu dữ liệu đầu vào của bạn không được mã hóa UTF-8, thì tất nhiên, bạn phải sử .decode()dụng mã hóa thích hợp. Nếu không có gì được đưa ra, python sẽ giả định ASCII, điều này hiển nhiên không thành công trên các ký tự không phải ASCII.


1
Lý do gây ra lỗi là Python đang cố gắng tự động giải mã nó từ mã hóa mặc định, ASCII, để sau đó nó có thể mã hóa nó như anh ta đã chỉ định, thành UTF-8. Vì dữ liệu không phải là ASCII hợp lệ nên nó không hoạt động.
agf

7
chắc chắn, nhưng nếu đó là dữ liệu được mã hóa UTF8 (như tôi đoán), thì .decode('utf-8')bạn có nên làm theo mẹo hay không?
ch3ka

Chắc chắn, bạn có thể đúng. Tôi chỉ giải thích lý do tại sao bạn gặp lỗi cụ thể đó trong tình huống này.
agf

1
Hoàn hảo! Cảm ơn rât nhiều. Vì vậy, nó chỉ ra rằng đó là .decode ('latin-1') - điều này có ý nghĩa bởi vì nó đã đưa ra cho tôi vấn đề. Lần nữa! Cảm ơn bạn!
jelkimantis

Giải pháp của bạn phù hợp với một số trường hợp, nhưng trong trường hợp nếu tôi sử dụng điều này thì tôi gặp một lỗi khác codec 'ascii' không thể mã hóa ký tự u '\ xf1' ở vị trí 2: thứ tự không trong phạm vi (128)
Vikash Mishra

84

Chỉ cần thêm các dòng này vào mã của bạn:

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

5
`` AttributeError: module 'sys' không có thuộc tính 'setdefaultencoding' dường như không hoạt động trong Python 3
skjern 16/02/18

Woot woot! Điều này đã giúp tôi.
Shougo Makishima

1
Nó hoạt động cho Python 2.7 của tôi, lưu ý, tải lại (hệ thống) là cần thiết, nếu không, mã setdefaultencoding sẽ không thể truy cập được.
Yu Shen

1
Đó là điều duy nhất khiến nó hoạt động với tôi trong số rất nhiều câu hỏi SO. Cám ơn rất nhiều!
Freedo

tên 'tải lại' không được xác định
Davide

28

cho người dùng Python 3. bạn có thể làm

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

nó cũng hoạt động với bình :)


1
Đây là lần đầu tiên tôi giúp ai đó ở đây. cảm thấy tốt biết tôi đã giúp :)
Skrmnghrd

1
Và bạn cũng đã giúp tôi :) Tất cả các câu trả lời khác không hoạt động để đọc tệp. Bây giờ tôi cần phải tìm hiểu làm thế nào để sửa chữa nó cũng cho văn bản;)
user2194898

bạn có thể gửi cho tôi liên kết của mã của bạn? Tôi sẽ cố gắng giúp
Skrmnghrd

9

Nguyên nhân chính gây ra lỗi là mã hóa mặc định do python giả định là ASCII. Do đó, nếu dữ liệu chuỗi được mã hóa encode('utf8')chứa ký tự nằm ngoài phạm vi ASCII, ví dụ như đối với một chuỗi như 'hgvcj 터 파크 387', python sẽ gây ra lỗi vì chuỗi không ở định dạng mã hóa mong đợi.

Nếu bạn đang sử dụng phiên bản python sớm hơn phiên bản 3.5, một bản sửa lỗi đáng tin cậy sẽ là đặt mã hóa mặc định do python giả định thành utf8:

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

Bằng cách này, python sẽ có thể đoán trước các ký tự trong một chuỗi nằm ngoài phạm vi ASCII.

Tuy nhiên, nếu bạn đang sử dụng phiên bản python 3.5 trở lên, hàm reload () không khả dụng, vì vậy bạn sẽ phải sửa nó bằng cách sử dụng giải mã, ví dụ:

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

sự khác biệt giữa các câu trả lời và mỏ của bạn là gì
khelili Miliana

1
Chi tiết hơn. Mọi người thường thấy các chi tiết nhân quả hữu ích. Và mã của bạn hoạt động btw, không có ý định phủ định.
Temi Fakunle,

1
tải lại có sẵn trong Python 3, bạn chỉ cần nhập nó. từ tải lại nhập nhập
Meow

@Meow nhưng không có sys.setdefaultencoding trong Python 3. Vì vậy, trong ngữ cảnh tương thích py2 \ py3, một số kiểm tra sẽ thực hiện, có thể là sys.getdefaultencoding (). Sẽ đánh giá cao một lời khuyên về vấn đề đó. stackoverflow.com/questions/28127513/…
Konst54

2

Đối với người dùng Python 3:

thay đổi mã hóa từ 'ascii' thành 'latin1' hoạt động.

Ngoài ra, bạn có thể thử tự động tìm mã hóa bằng cách đọc 10000 byte hàng đầu bằng đoạn mã dưới đây:

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

2

Máy tính của tôi đã đặt sai ngôn ngữ.

Lần đầu tiên tôi làm

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

locale.getpreferredencoding(False)là hàm được gọi bởi open()khi bạn không cung cấp mã hóa . Đầu ra phải là 'UTF-8', nhưng trong trường hợp này, nó là một số biến thể của ASCII .

Sau đó, tôi chạy lệnh bash localevà nhận được kết quả này

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

Vì vậy, tôi đang sử dụng ngôn ngữ Ubuntu mặc định, khiến Python mở tệp dưới dạng ASCII thay vì UTF-8. Tôi phải đặt ngôn ngữ của mình thànhen_US.UTF-8

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

Nếu bạn không thể thay đổi toàn bộ hệ thống ngôn ngữ, bạn có thể gọi tất cả mã Python của mình như sau:

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

hoặc làm

export PYTHONIOENCODING="UTF-8"

để đặt nó trong shell mà bạn chạy nó vào.


1

nếu bạn gặp sự cố này khi chạy certbot trong khi tạo hoặc gia hạn chứng chỉ, vui lòng sử dụng phương pháp sau

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

Lệnh đó đã tìm thấy ký tự vi phạm "´" trong một tệp .conf trong nhận xét. Sau khi xóa nó (bạn có thể chỉnh sửa bình luận theo ý muốn) và tải lại nginx, mọi thứ hoạt động trở lại.

Nguồn: https://github.com/certbot/certbot/issues/5236


0

Hoặc khi bạn xử lý văn bản bằng Python nếu đó là văn bản Unicode, hãy lưu ý rằng đó là Unicode.

Đặt text=u'unicode text'thay vào đó chỉ text='unicode text'.

Điều này đã làm việc trong trường hợp của tôi.


0

mở bằng mã hóa UTF 16 vì độ trễ và độ dài.

with open(csv_name_here, 'r', encoding="utf-16") as f:

0

Nó hoạt động bằng cách chỉ lấy đối số 'rb' đọc nhị phân thay vì đọc 'r'

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.