UnicodeDecodeError: 'utf8' codec tidak dapat mendekode byte 0x9c


289

Saya memiliki server soket yang seharusnya menerima karakter valid UTF-8 dari klien.

Masalahnya adalah beberapa klien (terutama peretas) mengirimkan semua jenis data yang salah di atasnya.

Saya dapat dengan mudah membedakan klien asli, tetapi saya masuk ke file semua data yang dikirim sehingga saya bisa menganalisisnya nanti.

Terkadang saya mendapatkan karakter seperti ini œyang menyebabkan UnicodeDecodeErrorkesalahan.

Saya harus bisa membuat string UTF-8 dengan atau tanpa karakter tersebut.


Memperbarui:

Untuk kasus khusus saya, layanan socket adalah MTA dan karenanya saya hanya berharap untuk menerima perintah ASCII seperti:

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

Saya mencatat semua ini di JSON.

Kemudian beberapa orang di luar sana tanpa niat baik memutuskan untuk menjual semua jenis sampah.

Itulah sebabnya untuk kasus khusus saya, sangat oke untuk menghapus karakter non ASCII.


1
apakah string keluar dari file atau soket? dapatkah Anda memposting contoh kode tentang bagaimana string dikodekan dan didekodekan sebelum dikirim melalui socket / filehandler?
devsnd

Apakah saya menulis atau tidak saya menulis bahwa string datang ke soket? Saya cukup membaca string dari soket dan dengan memasukkannya ke dalam kamus dan kemudian JSON untuk mengirimkannya. Fungsi JSON gagal karena karakter-karakter itu.
transilvlad

tolong cantumkan data sampel masalah Anda
Shubham Sharma

Jawaban:


343

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

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

atau

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

Catatan: Ini akan menghapus (mengabaikan) karakter yang dimaksud mengembalikan string tanpa mereka.

Bagi saya ini adalah kasus yang ideal karena saya menggunakannya sebagai perlindungan terhadap input non-ASCII yang tidak diizinkan oleh aplikasi saya.

Atau: Gunakan metode terbuka dari codecsmodul untuk membaca dalam file:

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

45
Ya, meskipun ini biasanya praktik buruk / berbahaya, karena Anda hanya akan kehilangan karakter. Lebih baik untuk menentukan atau mendeteksi pengkodean dari string input dan decode ke unicode terlebih dahulu, kemudian dikodekan sebagai UTF-8, misalnya:str.decode('cp1252').encode('utf-8')
Ben Hoyt

Dalam beberapa kasus ya Anda benar itu dapat menyebabkan masalah. Dalam kasus saya, saya tidak peduli tentang mereka karena mereka tampaknya karakter tambahan yang berasal dari pemformatan dan pemrograman yang buruk dari klien yang terhubung ke server socket saya.
transilvlad

Yang satu ini benar-benar membantu jika konten string sebenarnya tidak valid, dalam kasus saya '\xc0msterdam'yang berubah menjadi u'\ufffdmsterdam'ganti
PvdL

3
jika Anda berakhir di sini karena Anda mengalami masalah dalam membaca file, membuka file dalam mode biner mungkin membantu: open(file_name, "rb")dan kemudian menerapkan pendekatan Ben dari komentar di atas
kristian

opsi yang sama berlaku untuk lebih banyak lagi, misalnya untuk "something.decode ()"
Alexander Stohr

83

Mengubah mesin dari C ke Python melakukan trik untuk saya.

Engine adalah C:

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

Codec 'utf-8' tidak dapat mendekode byte 0x92 di posisi 18: byte start tidak valid

Engine adalah Python:

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

Tidak ada kesalahan untuk saya.


3
itu sebenarnya solusi yang bagus. Saya tidak tahu mengapa itu dibatalkan.
ℕʘʘḆḽḘ

Ini mungkin bukan ide yang baik jika Anda memiliki csvfile besar . Ini bisa membawa Anda ke OutOfMemorykesalahan atau restart kernel notebook Anda secara otomatis. Anda harus mengatur encodingkasus ini.
LucasBr

1
Jawaban yang sangat bagus. Terima kasih. Ini berhasil untuk saya. Saya memiliki "?" Di dalam karakter bentuk berlian yang menyebabkan masalah. Dengan mata biasa aku punya "" yang inci. Saya melakukan 2 hal untuk mencari tahu. a) df = pd.read_csv ('test.csv', n_rows = 10000). Ini bekerja sempurna tanpa mesin. Jadi saya menambahkan n_rows untuk mencari tahu baris mana yang memiliki kesalahan. b) df = pd.read_csv ('test.csv', engine = 'python'). Ini berhasil dan saya mencetak baris yang salah menggunakan df.iloc [36145], ini mencetak saya catatan yang salah.
Jagannath Banerjee

1
ini bekerja untuk saya juga ... Tidak yakin apa yang terjadi 'di bawah tenda' dan jika ini sebenarnya solusi yang bagus / baik / tepat dalam semua kasus, tetapi itu berhasil bagi saya;)
Chrisvdberge

1
Solusi bagus! Terima kasih banyak.
Pechi

62

Jenis masalah ini muncul bagi saya sekarang karena saya sudah pindah ke Python 3. Saya tidak tahu Python 2 hanya menggulung masalah dengan encoding file.

Saya menemukan penjelasan yang bagus tentang perbedaan ini dan bagaimana menemukan solusi setelah tidak ada yang berhasil bagi saya.

http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html

Singkatnya, untuk membuat Python 3 berperilaku semirip mungkin dengan Python 2 gunakan:

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

Namun, baca artikelnya, tidak ada satu ukuran cocok untuk semua solusi.


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

16
Saya bingung, bagaimana Anda memilih cp1252? Itu berhasil untuk saya, tetapi mengapa? Saya tidak tahu dan sekarang saya tersesat: /. Bisakah Anda menguraikan? Terima kasih banyak ! :)
Cyril N.

4
Bisakah Anda menyajikan opsi yang berfungsi untuk semua karakter? Apakah ada cara untuk mendeteksi karakter yang perlu diterjemahkan sehingga kode yang lebih umum dapat diimplementasikan? Saya melihat banyak orang melihat ini dan saya bertaruh untuk membuang beberapa bukan pilihan yang diinginkan seperti bagi saya.
transilvlad

Seperti yang Anda lihat, pertanyaan ini cukup populer. Pikirkan Anda dapat memperluas jawaban Anda dengan solusi yang lebih umum?
transilvlad

13
Tidak ada lagi solusi umum untuk "Tebak roulette penyandian"
Puppy

5
menemukannya menggunakan kombinasi pencarian web, keberuntungan dan intuisi: cp1252 adalahused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov

24

Saya memiliki masalah yang sama dengan UnicodeDecodeErrordan saya menyelesaikannya dengan baris ini. Tidak tahu apakah itu cara terbaik tetapi itu berhasil untuk saya.

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

13

yang pertama, Menggunakan get_encoding_type untuk mendapatkan tipe file encode:

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

yang kedua, buka file dengan tipe:

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

1
apa yang terjadi ketika kembali Tidak ada
Chop Labalagun

3

Hanya dalam kasus seseorang memiliki masalah yang sama. Saya menggunakan vim dengan YouCompleteMe , gagal memulai ycmd dengan pesan kesalahan ini, yang saya lakukan adalah:, export LC_CTYPE="en_US.UTF-8"masalahnya hilang.


2
Bagaimana ini berhubungan dengan pertanyaan ini?
transilvlad

1
Persis sama, jika Anda tahu cara kerja Anda menyelesaikan. Plugin Ycm adalah arsitektur socket, komunikasi antara klien dan server menggunakan socket, keduanya adalah modul python, tidak dapat men-decode paket jika pengaturan encoding salah
workplaylifecycle

Saya memiliki masalah yang sama. Bisakah Anda memberi tahu saya di mana harus meletakkannya export LC_CTYPE="en_US.UTF-8"?
Reman

@Remonn hai, Anda tahu kami punya file profil untuk bash? Letakkan di dalam.
workplaylifecycle

@hylepo, saya menggunakan sistem windows :)
Reman

3

Apa yang dapat Anda lakukan jika Anda perlu membuat perubahan ke file, tetapi tidak tahu penyandian file? Jika Anda tahu penyandiannya kompatibel dengan ASCII dan hanya ingin memeriksa atau memodifikasi bagian ASCII, Anda dapat membuka file dengan penangan kesalahan surrogateescape:

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

0

Saya telah memecahkan masalah ini hanya dengan menambahkan

df = pd.read_csv(fileName,encoding='latin1')
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.