UnicodeDecodeError: ตัวแปลงสัญญาณ 'utf8' ไม่สามารถถอดรหัสไบต์ 0x9c


289

ฉันมีซ็อกเก็ตเซิร์ฟเวอร์ที่ควรจะได้รับอักขระที่ถูกต้อง UTF-8 จากลูกค้า

ปัญหาคือลูกค้าบางราย (ส่วนใหญ่แฮกเกอร์) กำลังส่งข้อมูลผิดประเภททั้งหมด

ฉันสามารถแยกความแตกต่างไคลเอนต์ของแท้ได้อย่างง่ายดาย แต่ฉันเข้าสู่ไฟล์ข้อมูลทั้งหมดที่ส่งเพื่อให้ฉันสามารถวิเคราะห์ได้ในภายหลัง

บางครั้งฉันได้รับตัวละครเช่นนี้œทำให้เกิดUnicodeDecodeErrorข้อผิดพลาด

ฉันต้องสามารถสร้างสตริง UTF-8 โดยมีหรือไม่มีอักขระเหล่านั้น


ปรับปรุง:

สำหรับกรณีของฉันบริการซ็อกเก็ตเป็น MTA และฉันคาดหวังว่าจะได้รับคำสั่ง ASCII เช่น:

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

ฉันบันทึกทั้งหมดนี้ใน JSON

จากนั้นบางคนก็ออกไปที่นั่นโดยไม่มีเจตนาดีตัดสินใจขายขยะทุกชนิด

นั่นเป็นเหตุผลสำหรับกรณีเฉพาะของฉันมันเป็นเรื่องที่ดีที่จะตัดอักขระที่ไม่ใช่ ASCII ออก


1
สตริงมาจากไฟล์หรือซ็อกเก็ตหรือไม่? คุณช่วยกรุณาโพสต์ตัวอย่างรหัสของวิธีการเข้ารหัสสตริงสิ้นสุดการถอดรหัสก่อนที่จะส่งผ่านซ็อกเก็ต / filehandler?
devsnd

ฉันเขียนหรือไม่เขียนว่าสายอักขระมาเหนือซ็อกเก็ตหรือไม่? ฉันเพียงแค่อ่านสตริงจากซ็อกเก็ตและใส่ไว้ในพจนานุกรมแล้ว JSON มันเพื่อส่งมันไป ฟังก์ชัน JSON ล้มเหลวเนื่องจากอักขระเหล่านั้น
transilvlad

คุณช่วยใส่ข้อมูลตัวอย่างปัญหาให้คุณได้ไหม
Shubham Sharma

คำตอบ:


343

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

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

หรือ

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

หมายเหตุ: สิ่งนี้จะตัด (ละเว้น) อักขระที่มีปัญหาส่งคืนสตริงโดยไม่มีอักขระ

สำหรับฉันนี่เป็นกรณีที่เหมาะเนื่องจากฉันใช้มันเพื่อป้องกันอินพุตที่ไม่ใช่ ASCII ซึ่งไม่ได้รับอนุญาตจากแอปพลิเคชันของฉัน

อีกวิธีหนึ่ง:ใช้วิธีการเปิดจากcodecsโมดูลเพื่ออ่านในไฟล์:

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

45
ใช่แม้ว่าโดยปกติจะเป็นการปฏิบัติ / อันตรายที่ไม่ดีเพราะคุณจะสูญเสียอักขระไป ดีกว่าที่จะกำหนดหรือตรวจจับการเข้ารหัสของสายป้อนข้อมูลและถอดรหัสเป็น Unicode ก่อนจากนั้นเข้ารหัสเป็น UTF-8 เช่น:str.decode('cp1252').encode('utf-8')
Ben Hoyt

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

อันนี้จริง ๆ แล้วช่วยถ้าเนื้อหาของสายอักขระไม่ถูกต้องจริง ๆ , ในกรณีของฉัน'\xc0msterdam'ซึ่งเปลี่ยนเป็นu'\ufffdmsterdam'แทนที่
PvdL

3
หากคุณลงเอยที่นี่เพราะคุณมีปัญหาในการอ่านไฟล์การเปิดไฟล์ในโหมดไบนารี่อาจช่วยได้: open(file_name, "rb")จากนั้นใช้วิธีการของเบ็นจากความคิดเห็นข้างต้น
kristian

ตัวเลือกเดียวกันนี้ใช้ได้กับสิ่งอื่น ๆ อีกมากมายเช่น "something.decode ()"
Alexander Stohr

83

การเปลี่ยนเอนจิ้นจาก C เป็น Python นั้นเป็นเคล็ดลับสำหรับฉัน

เครื่องยนต์คือ C:

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

ตัวแปลงสัญญาณ 'utf-8' ไม่สามารถถอดรหัสไบต์ 0x92 ในตำแหน่งที่ 18: ไบต์เริ่มต้นที่ไม่ถูกต้อง

Engine คือ Python:

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

ไม่มีข้อผิดพลาดสำหรับฉัน


3
นั่นเป็นทางออกที่ดีจริงๆ ฉันไม่รู้ว่าทำไมมันถึงถูกลดระดับลง
ℕʘʘḆḽḘ

นี่อาจไม่ใช่ความคิดที่ดีถ้าคุณมีcsvไฟล์ขนาดใหญ่ อาจทำให้คุณเกิดOutOfMemoryข้อผิดพลาดหรือรีสตาร์ทเคอร์เนลโน้ตบุ๊คของคุณโดยอัตโนมัติ คุณควรตั้งค่าencodingในกรณีนี้
LucasBr

1
คำตอบที่ยอดเยี่ยม ขอบคุณ. สิ่งนี้ใช้ได้สำหรับฉัน ฉันมี "?" ภายในตัวละครรูปร่างเพชรที่ทำให้เกิดปัญหา ด้วยตาเปล่าฉันมี "" ซึ่งเป็นนิ้ว ฉันทำ 2 สิ่งเพื่อหาความจริง a) df = pd.read_csv ('test.csv', n_rows = 10,000) สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบหากไม่มีเครื่องยนต์ ดังนั้นฉันจึงเพิ่ม n_rows เพื่อหาว่าแถวไหนมีข้อผิดพลาด b) df = pd.read_csv ('test.csv', engine = 'python') สิ่งนี้ใช้ได้ผลและฉันพิมพ์แถวที่มีข้อผิดพลาดโดยใช้ df.iloc [36145] สิ่งนี้พิมพ์บันทึกข้อผิดพลาดให้ฉัน
Jagannath Banerjee

1
นี้ทำงานให้ฉันเกินไป ... ไม่แน่ใจว่าสิ่งที่เกิดขึ้นภายใต้ฝากระโปรงและถ้าเรื่องนี้เป็นจริงที่ดี / ดี / วิธีที่เหมาะสมในทุกกรณี แต่มันได้เคล็ดลับสำหรับผม;)
Chrisvdberge

1
สุดยอดทางออก! ขอบคุณมาก.
Pechi

62

ปัญหาประเภทนี้เพิ่มขึ้นสำหรับฉันตอนนี้ที่ฉันย้ายไปยัง Python 3 ฉันไม่รู้เลยว่า Python 2 เป็นเพียงการม้วนปัญหาใด ๆ ด้วยการเข้ารหัสไฟล์

ฉันพบคำอธิบายที่ดีเกี่ยวกับความแตกต่างและวิธีการหาวิธีการแก้ปัญหาหลังจากที่ไม่ได้ทำงานกับฉัน

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

กล่าวโดยสรุปคือการทำให้ Python 3 มีพฤติกรรมคล้ายกันมากที่สุดกับการใช้ Python 2:

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

อย่างไรก็ตามอ่านบทความไม่มีขนาดที่เหมาะกับการแก้ปัญหาทั้งหมด


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

16
ฉันสับสนคุณเลือก cp1252 อย่างไร มันใช้งานได้สำหรับฉัน แต่ทำไม ฉันไม่รู้และตอนนี้ฉันหลงทาง / คุณสามารถทำอย่างละเอียด? ขอบคุณมาก ! :)
Cyril N.

4
คุณช่วยแสดงตัวเลือกที่ใช้ได้กับตัวละครทั้งหมดหรือไม่? มีวิธีการตรวจสอบอักขระที่ต้องถอดรหัสเพื่อให้สามารถใช้รหัสทั่วไปได้มากกว่านี้หรือไม่? ฉันเห็นคนจำนวนมากกำลังดูที่นี้และฉันเดิมพันสำหรับการทิ้งบางอย่างไม่ใช่ตัวเลือกที่ต้องการเช่นเดียวกับฉัน
transilvlad

อย่างที่คุณเห็นคำถามนี้ค่อนข้างได้รับความนิยม คิดว่าคุณสามารถขยายคำตอบของคุณด้วยโซลูชันที่กว้างกว่าเดิมได้หรือไม่?
transilvlad

13
ไม่มีวิธีการทั่วไปมากขึ้นในการ "เดารูเล็ตการเข้ารหัส"
ลูกสุนัข

5
พบมันโดยใช้การค้นหาเว็บร่วมกันโชคและปรีชา: cp1252 คือused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov

24

ฉันมีปัญหาเดียวกันกับUnicodeDecodeErrorและฉันแก้ไขมันด้วยสายนี้ ไม่รู้ว่าเป็นวิธีที่ดีที่สุดหรือเปล่า แต่มันก็ใช้ได้ผลสำหรับฉัน

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

13

วิธีแรกใช้ get_encoding_type เพื่อรับชนิดของการเข้ารหัส:

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

ที่สองเปิดไฟล์ด้วยประเภท:

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

1
จะเกิดอะไรขึ้นเมื่อมันกลับมาไม่มี
Chop Labalagun

3

ในกรณีที่ใครบางคนมีปัญหาเดียวกัน ฉันกำลังใช้ vim กับYouCompleteMeไม่สามารถเริ่ม ycmd ด้วยข้อความแสดงข้อผิดพลาดสิ่งที่ฉันทำคือ: export LC_CTYPE="en_US.UTF-8"ปัญหาหายไป


2
สิ่งนี้เกี่ยวข้องกับคำถามนี้อย่างไร
transilvlad

1
เหมือนกันถ้าคุณรู้ว่าคุณทำงานอย่างไร ปลั๊กอิน Ycm เป็นสถาปัตยกรรมซ็อกเก็ตการสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์กำลังใช้ซ็อกเก็ตทั้งสองเป็นโมดูลหลามไม่สามารถถอดรหัสแพ็กเก็ตได้หากการตั้งค่าการเข้ารหัสไม่ถูกต้อง
workplaylifecycle

ผมมีปัญหาเดียวกัน. คุณช่วยบอกฉันได้ที่ไหนว่าจะใส่ไว้export LC_CTYPE="en_US.UTF-8"ที่ไหน?
Reman

@Remonn สวัสดีคุณรู้ไหมว่าเรามีไฟล์โปรไฟล์สำหรับทุบตี? ใส่ใน.
workplaylifecycle

@hylepo ฉันใช้ระบบ windows :)
Reman

3

คุณจะทำอย่างไรถ้าคุณต้องการเปลี่ยนแปลงไฟล์ แต่ไม่รู้การเข้ารหัสไฟล์? หากคุณรู้ว่าการเข้ารหัสนั้นเข้ากันได้กับ ASCII และต้องการตรวจสอบหรือแก้ไขส่วน ASCII เท่านั้นคุณสามารถเปิดไฟล์ด้วยตัวจัดการข้อผิดพลาด surrogateescape:

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

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