UnicodeDecodeError: 'utf8' codec không thể giải mã byte 0x9c


289

Tôi có một máy chủ ổ cắm được cho là nhận các ký tự hợp lệ UTF-8 từ các máy khách.

Vấn đề là một số khách hàng (chủ yếu là tin tặc) đang gửi tất cả các loại dữ liệu sai về nó.

Tôi có thể dễ dàng phân biệt máy khách chính hãng, nhưng tôi đang đăng nhập vào tệp tất cả dữ liệu được gửi để tôi có thể phân tích sau.

Đôi khi tôi nhận được các ký tự như thế này œgây ra UnicodeDecodeErrorlỗi.

Tôi cần có khả năng tạo chuỗi UTF-8 có hoặc không có các ký tự đó.


Cập nhật:

Đối với trường hợp cụ thể của tôi, dịch vụ ổ cắm là một MTA và do đó tôi chỉ mong nhận được các lệnh ASCII như:

EHLO example.com
MAIL FROM: <john.doe@example.com>
...

Tôi đã đăng nhập tất cả những thứ này trong JSON.

Sau đó, một số người không có ý định tốt đã quyết định bán tất cả các loại rác.

Đó là lý do tại sao đối với trường hợp cụ thể của tôi, việc loại bỏ các ký tự không phải ASCII là hoàn toàn ổn.


1
chuỗi ra khỏi một tập tin hoặc một ổ cắm? bạn có thể vui lòng gửi các ví dụ mã về cách chuỗi được mã hóa kết thúc được giải mã trước khi nó được gửi qua socket / filehandler không?
devsnd

Tôi đã viết hay tôi không viết rằng chuỗi đi qua ổ cắm? Tôi chỉ đơn giản là đọc chuỗi từ ổ cắm và để đưa nó vào một từ điển và sau đó JSON nó để gửi nó theo. Hàm JSON không thành công do các ký tự đó.
transilvlad

bạn có thể vui lòng đặt dữ liệu mẫu của bạn về vấn đề không
Shubham Sharma

Câu trả lời:


343

http://docs.python.org/howto/unicode.html#the-unicode-type

str = unicode(str, errors='replace')

hoặc là

str = unicode(str, errors='ignore')

Lưu ý: Điều này sẽ loại bỏ (bỏ qua) các ký tự trong câu hỏi trả về chuỗi mà không có chúng.

Đối với tôi đây là trường hợp lý tưởng vì tôi đang sử dụng nó như là sự bảo vệ chống lại đầu vào không phải ASCII mà ứng dụng của tôi không cho phép.

Cách khác: Sử dụng phương thức mở từ codecsmô-đun để đọc trong tệp:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:

45
Có, mặc dù điều này thường là thực hành xấu / nguy hiểm, bởi vì bạn sẽ chỉ mất nhân vật. Tốt hơn là xác định hoặc phát hiện mã hóa chuỗi đầu vào và giải mã nó thành unicode trước, sau đó mã hóa thành UTF-8, ví dụ:str.decode('cp1252').encode('utf-8')
Ben Hoyt

Trong một số trường hợp có bạn đúng nó có thể gây ra vấn đề. Trong trường hợp của tôi, tôi không quan tâm đến họ vì họ dường như là những nhân vật phụ xuất phát từ định dạng và lập trình xấu của các máy khách kết nối với máy chủ ổ cắm của tôi.
transilvlad

Điều này thực sự có ích nếu nội dung của chuỗi thực sự không hợp lệ, trong trường hợp của tôi '\xc0msterdam', nó chuyển sang u'\ufffdmsterdam'thay thế
PvdL

3
nếu bạn kết thúc ở đây vì bạn gặp vấn đề khi đọc tệp, mở tệp ở chế độ nhị phân có thể giúp ích: open(file_name, "rb")và sau đó áp dụng cách tiếp cận của Ben từ các nhận xét ở trên
kristian

tùy chọn tương tự áp dụng cho thậm chí nhiều hơn, ví dụ: "Something.decode ()"
Alexander Stohr

83

Việc thay đổi công cụ từ C thành Python đã giúp tôi rất nhiều.

Động cơ là C:

pd.read_csv(gdp_path, sep='\t', engine='c')

'utf-8' codec không thể giải mã byte 0x92 ở vị trí 18: byte bắt đầu không hợp lệ

Công cụ là Python:

pd.read_csv(gdp_path, sep='\t', engine='python')

Không có lỗi cho tôi.


3
Đó thực sự là một giải pháp tốt. tôi không biết tại sao nó bị hạ cấp.
18 giờ 34

Đây có thể không phải là một ý tưởng tốt nếu bạn có một csvtập tin lớn . Nó có thể dẫn bạn đến một OutOfMemorylỗi hoặc tự động khởi động lại kernel của máy tính xách tay của bạn. Bạn nên đặt trong encodingtrường hợp này.
LucasBr

1
Câu trả lời tuyệt vời. Cảm ơn bạn. Điều này làm việc cho tôi. Tôi có "?" Bên trong một nhân vật hình kim cương gây ra vấn đề. Với đôi mắt đơn giản, tôi có '"" là inch. Tôi đã làm 2 điều để tìm ra. a) df = pd.read_csv ('test.csv', n_rows = 10000). Điều này làm việc hoàn hảo mà không cần động cơ. Vì vậy, tôi đã tăng n_rows để tìm ra hàng nào có lỗi. b) df = pd.read_csv ('test.csv', engine = 'python'). Điều này đã làm việc và tôi đã in hàng bị lỗi bằng cách sử dụng df.iloc [36145], điều này đã in cho tôi bản ghi bị lỗi.
Jagannath Banerjee

1
này làm việc cho tôi quá ... Không chắc những gì đang xảy ra 'dưới mui xe' và nếu điều này thực sự là một đẹp / tốt / giải pháp thích hợp trong mọi trường hợp, nhưng nó đã làm các trick cho tôi;)
Chrisvdberge

1
Giải pháp tuyệt vời! Cảm ơn bạn rất nhiều.
Pechi

62

Loại vấn đề này xảy ra với tôi khi tôi chuyển sang Python 3. Tôi không biết Python 2 chỉ đơn giản là xử lý mọi vấn đề với mã hóa tập tin.

Tôi tìm thấy lời giải thích tốt đẹp này về sự khác biệt và cách tìm ra giải pháp sau khi không có cách nào ở trên làm việc cho tôi.

http://python-notes.curiouseffic.org/en/latest/python3/text_file_ Processing.html

Nói tóm lại, để làm cho Python 3 hoạt động tương tự nhất có thể với Python 2, hãy sử dụng:

with open(filename, encoding="latin-1") as datafile:
    # work on datafile here

Tuy nhiên, đọc bài viết, không có một kích thước phù hợp với tất cả các giải pháp.


29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ

16
Tôi bối rối, làm thế nào bạn chọn cp1252? Nó làm việc cho tôi, nhưng tại sao? Tôi không biết và bây giờ tôi bị mất: /. Bạn có thể giải thích? Cảm ơn rất nhiều ! :)
Cyril N.

4
Bạn có thể trình bày một tùy chọn hoạt động cho tất cả các nhân vật? Có cách nào để phát hiện các ký tự cần được giải mã để mã chung hơn có thể được thực hiện không? Tôi thấy nhiều người đang nhìn vào điều này và tôi cá rằng một số loại bỏ không phải là lựa chọn mong muốn giống như nó là dành cho tôi.
transilvlad

Như bạn có thể thấy câu hỏi này có khá phổ biến. Nghĩ rằng bạn có thể mở rộng câu trả lời của bạn với một giải pháp chung chung hơn?
transilvlad

13
Không có giải pháp chung nào hơn cho "Đoán roulette mã hóa"
Puppy

5
tìm thấy nó bằng cách sử dụng kết hợp tìm kiếm trên web, may mắn và trực giác: cp1252used by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov

24

Tôi đã có cùng một vấn đề UnicodeDecodeErrorvà tôi đã giải quyết nó với dòng này. Không biết là cách tốt nhất nhưng nó hiệu quả với tôi.

str = str.decode('unicode_escape').encode('utf-8')

13

Đầu tiên, Sử dụng get_encoding_type để lấy loại mã hóa:

import os    
from chardet import detect

# get file encoding type
def get_encoding_type(file):
    with open(file, 'rb') as f:
        rawdata = f.read()
    return detect(rawdata)['encoding']

thứ hai, mở các tệp với loại:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')

1
Điều gì xảy ra khi nó trở về Không
Chop Labalagun

3

Chỉ trong trường hợp ai đó có cùng một vấn đề. Tôi đang sử dụng vim với YouCompleteMe , không thể khởi động ycmd với thông báo lỗi này, điều tôi đã làm là : export LC_CTYPE="en_US.UTF-8", vấn đề đã biến mất.


2
Làm thế nào điều này liên quan đến câu hỏi này?
transilvlad

1
Chính xác là như vậy, nếu bạn biết cách bạn hoạt động. Plugin Ycm là kiến ​​trúc ổ cắm, giao tiếp giữa máy khách và máy chủ đang sử dụng ổ cắm, cả hai đều là mô-đun python, không thể giải mã các gói nếu cài đặt mã hóa không chính xác
workplaylifecycle

Tôi có cùng một vấn đề. Bạn có thể vui lòng cho tôi biết nơi để đặt export LC_CTYPE="en_US.UTF-8"?
Reman

@Remonn hi, bạn biết chúng tôi có tập tin hồ sơ cho bash không? Đặt vào trong.
workplaylifecycl

@hylepo, tôi đang sử dụng hệ thống windows :)
Reman

3

Bạn có thể làm gì nếu bạn cần thay đổi một tệp, nhưng không biết mã hóa của tệp? Nếu bạn biết mã hóa tương thích với ASCII và chỉ muốn kiểm tra hoặc sửa đổi các phần ASCII, bạn có thể mở tệp bằng trình xử lý lỗi surrogateescape:

with open(fname, 'r', encoding="ascii", errors="surrogateescape") as f:
    data = f.read()

0

Tôi đã giải quyết vấn đề này chỉ bằng cách thêm

df = pd.read_csv(fileName,encoding='latin1')
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.