u '\ ufeff' ในสตริง Python


153

ฉันได้รับข้อผิดพลาดกับลายดังต่อไปนี้:

UnicodeEncodeError: 'ascii' codec can't encode character u'\ufeff' in position 155: ordinal not in range(128)

ไม่แน่ใจว่าu'\ufeff'เป็นอะไรมันจะปรากฏขึ้นเมื่อฉันขูดเว็บ ฉันจะแก้ไขสถานการณ์ได้อย่างไร .replace()วิธีสตริงไม่ได้ทำงานกับมัน


6
ข้อมูลนี้มาจากไหน คุณพยายามทำอะไร กรุณาใส่รหัสหลามของคุณ

7
บังเอิญฉันพบว่า. แทนที่ () ทำงานในงูหลามที่ทันสมัยถ้าฉันจำตัวบ่งชี้ unicode: s.replace (u '\ ufeff', '')
Doug Bradshaw

@DougBradshaw เมื่อคุณพูดว่า "modern python" คุณหมายถึง 2.7+ หรือ 3.0+ หรือไม่
teewuane

จุดดี. ความหมาย 2.7+
Doug Bradshaw

คำตอบ:


184

อักขระ Unicode U+FEFFเป็นเครื่องหมายคำสั่งไบต์หรือ BOM และใช้เพื่อบอกความแตกต่างระหว่างการเข้ารหัส UTF-16 ขนาดใหญ่และขนาดเล็ก หากคุณถอดรหัสเว็บเพจโดยใช้ตัวแปลงสัญญาณที่ถูกต้อง Python จะลบมันให้คุณ ตัวอย่าง:

#!python2
#coding: utf8
u = u'ABC'
e8 = u.encode('utf-8')        # encode without BOM
e8s = u.encode('utf-8-sig')   # encode with BOM
e16 = u.encode('utf-16')      # encode with BOM
e16le = u.encode('utf-16le')  # encode without BOM
e16be = u.encode('utf-16be')  # encode without BOM
print 'utf-8     %r' % e8
print 'utf-8-sig %r' % e8s
print 'utf-16    %r' % e16
print 'utf-16le  %r' % e16le
print 'utf-16be  %r' % e16be
print
print 'utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8')
print 'utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig')
print 'utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16')
print 'utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le')

โปรดทราบว่าEF BB BFเป็น BOM ที่เข้ารหัส UTF-8 ไม่จำเป็นสำหรับ UTF-8 แต่ทำหน้าที่เป็นลายเซ็นเท่านั้น (โดยปกติคือบน Windows)

เอาท์พุท:

utf-8     'ABC'
utf-8-sig '\xef\xbb\xbfABC'
utf-16    '\xff\xfeA\x00B\x00C\x00'    # Adds BOM and encodes using native processor endian-ness.
utf-16le  'A\x00B\x00C\x00'
utf-16be  '\x00A\x00B\x00C'

utf-8  w/ BOM decoded with utf-8     u'\ufeffABC'    # doesn't remove BOM if present.
utf-8  w/ BOM decoded with utf-8-sig u'ABC'          # removes BOM if present.
utf-16 w/ BOM decoded with utf-16    u'ABC'          # *requires* BOM to be present.
utf-16 w/ BOM decoded with utf-16le  u'\ufeffABC'    # doesn't remove BOM if present.

โปรดทราบว่าutf-16ตัวแปลงสัญญาณต้องมี BOM อยู่หรือ Python ไม่ทราบว่าข้อมูลมีขนาดใหญ่หรือเล็ก


201

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

ถ้าไม่มีมัน BOM จะรวมอยู่ในผลการอ่าน:

>>> f = open('file', mode='r')
>>> f.read()
'\ufefftest'

ให้การเข้ารหัสที่ถูกต้อง BOM จะถูกละเว้นในผลลัพธ์:

>>> f = open('file', mode='r', encoding='utf-8-sig')
>>> f.read()
'test'

แค่ 2 เซ็นต์ของฉัน


13
ขอบคุณนี่เป็นทางออกที่แท้จริงและควรเป็นคำตอบที่ยอมรับได้ ในขณะที่นี่เป็นข้อมูลเชิงลึกที่ดีเกี่ยวกับสาเหตุที่มีสตริงคนส่วนใหญ่มาที่นี่กำลังมองหาวิธีการแก้ปัญหาที่ตรงไปตรงมาและนี่คือมัน
neurino

3
มีปัญหาเดียวกันกับ csv DictReader ที่อ่านไฟล์ csv ที่บันทึกจาก Excel
LArntz

1
ใช่ Excel (แม้แต่ "csv" ที่สร้างโดย Excel) เป็นเรื่องร้อนจัด
osprey

4

ตัวละครนั้นเป็นBOMหรือ "Byte Order Mark" โดยปกติจะได้รับเป็นสองสามไบต์แรกของไฟล์โดยบอกวิธีตีความการเข้ารหัสของข้อมูลที่เหลือ คุณสามารถลบตัวละครเพื่อดำเนินการต่อ แม้ว่าข้อผิดพลาดจะบอกว่าคุณพยายามแปลงเป็น 'ascii' คุณควรเลือกการเข้ารหัสอีกครั้งสำหรับสิ่งที่คุณพยายามจะทำ


4

เนื้อหาที่คุณกำลังทำการขูดมีการเข้ารหัสในหน่วย Unicode แทนที่จะเป็นข้อความ ASCII และคุณได้รับตัวละครที่ไม่ได้แปลงเป็น ASCII 'การแปล' ที่ถูกต้องจะขึ้นอยู่กับหน้าเว็บดั้งเดิมที่คิดว่าเป็น หน้ายูนิโค้ดของไพ ธ อนให้พื้นหลังว่ามันทำงานอย่างไร

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


0

นี่คือคำตอบจาก Mark Tolonen สตริงรวมภาษาต่างๆของคำว่า 'ทดสอบ' ซึ่งคั่นด้วย '|' เพื่อให้คุณเห็นความแตกต่าง

u = u'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
e8 = u.encode('utf-8')        # encode without BOM
e8s = u.encode('utf-8-sig')   # encode with BOM
e16 = u.encode('utf-16')      # encode with BOM
e16le = u.encode('utf-16le')  # encode without BOM
e16be = u.encode('utf-16be')  # encode without BOM
print('utf-8     %r' % e8)
print('utf-8-sig %r' % e8s)
print('utf-16    %r' % e16)
print('utf-16le  %r' % e16le)
print('utf-16be  %r' % e16be)
print()
print('utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8'))
print('utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig'))
print('utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16'))
print('utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le'))

นี่คือการทดสอบการทำงาน:

>>> u = u'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> e8 = u.encode('utf-8')        # encode without BOM
>>> e8s = u.encode('utf-8-sig')   # encode with BOM
>>> e16 = u.encode('utf-16')      # encode with BOM
>>> e16le = u.encode('utf-16le')  # encode without BOM
>>> e16be = u.encode('utf-16be')  # encode without BOM
>>> print('utf-8     %r' % e8)
utf-8     b'ABCtest\xce\xb2\xe8\xb2\x9d\xe5\xa1\x94\xec\x9c\x84m\xc3\xa1sb\xc3\xaata|test|\xd8\xa7\xd8\xae\xd8\xaa\xd8\xa8\xd8\xa7\xd8\xb1|\xe6\xb5\x8b\xe8\xaf\x95|\xe6\xb8\xac\xe8\xa9\xa6|\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88|\xe0\xa4\xaa\xe0\xa4\xb0\xe0\xa5\x80\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb7\xe0\xa4\xbe|\xe0\xb4\xaa\xe0\xb4\xb0\xe0\xb4\xbf\xe0\xb4\xb6\xe0\xb5\x8b\xe0\xb4\xa7\xe0\xb4\xa8|\xd7\xa4\xd6\xbc\xd7\xa8\xd7\x95\xd7\x91\xd7\x99\xd7\xa8\xd7\x9f|ki\xe1\xbb\x83m tra|\xc3\x96l\xc3\xa7ek|'
>>> print('utf-8-sig %r' % e8s)
utf-8-sig b'\xef\xbb\xbfABCtest\xce\xb2\xe8\xb2\x9d\xe5\xa1\x94\xec\x9c\x84m\xc3\xa1sb\xc3\xaata|test|\xd8\xa7\xd8\xae\xd8\xaa\xd8\xa8\xd8\xa7\xd8\xb1|\xe6\xb5\x8b\xe8\xaf\x95|\xe6\xb8\xac\xe8\xa9\xa6|\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88|\xe0\xa4\xaa\xe0\xa4\xb0\xe0\xa5\x80\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb7\xe0\xa4\xbe|\xe0\xb4\xaa\xe0\xb4\xb0\xe0\xb4\xbf\xe0\xb4\xb6\xe0\xb5\x8b\xe0\xb4\xa7\xe0\xb4\xa8|\xd7\xa4\xd6\xbc\xd7\xa8\xd7\x95\xd7\x91\xd7\x99\xd7\xa8\xd7\x9f|ki\xe1\xbb\x83m tra|\xc3\x96l\xc3\xa7ek|'
>>> print('utf-16    %r' % e16)
utf-16    b"\xff\xfeA\x00B\x00C\x00t\x00e\x00s\x00t\x00\xb2\x03\x9d\x8cTX\x04\xc7m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x00'\x06.\x06*\x06(\x06'\x061\x06|\x00Km\xd5\x8b|\x00,nf\x8a|\x00\xc60\xb90\xc80|\x00*\t0\t@\t\x15\tM\t7\t>\t|\x00*\r0\r?\r6\rK\r'\r(\r|\x00\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x05|\x00k\x00i\x00\xc3\x1em\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|\x00"
>>> print('utf-16le  %r' % e16le)
utf-16le  b"A\x00B\x00C\x00t\x00e\x00s\x00t\x00\xb2\x03\x9d\x8cTX\x04\xc7m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x00'\x06.\x06*\x06(\x06'\x061\x06|\x00Km\xd5\x8b|\x00,nf\x8a|\x00\xc60\xb90\xc80|\x00*\t0\t@\t\x15\tM\t7\t>\t|\x00*\r0\r?\r6\rK\r'\r(\r|\x00\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x05|\x00k\x00i\x00\xc3\x1em\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|\x00"
>>> print('utf-16be  %r' % e16be)
utf-16be  b"\x00A\x00B\x00C\x00t\x00e\x00s\x00t\x03\xb2\x8c\x9dXT\xc7\x04\x00m\x00\xe1\x00s\x00b\x00\xea\x00t\x00a\x00|\x00t\x00e\x00s\x00t\x00|\x06'\x06.\x06*\x06(\x06'\x061\x00|mK\x8b\xd5\x00|n,\x8af\x00|0\xc60\xb90\xc8\x00|\t*\t0\t@\t\x15\tM\t7\t>\x00|\r*\r0\r?\r6\rK\r'\r(\x00|\x05\xe4\x05\xbc\x05\xe8\x05\xd5\x05\xd1\x05\xd9\x05\xe8\x05\xdf\x00|\x00k\x00i\x1e\xc3\x00m\x00 \x00t\x00r\x00a\x00|\x00\xd6\x00l\x00\xe7\x00e\x00k\x00|"
>>> print()

>>> print('utf-8  w/ BOM decoded with utf-8     %r' % e8s.decode('utf-8'))
utf-8  w/ BOM decoded with utf-8     '\ufeffABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-8  w/ BOM decoded with utf-8-sig %r' % e8s.decode('utf-8-sig'))
utf-8  w/ BOM decoded with utf-8-sig 'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-16 w/ BOM decoded with utf-16    %r' % e16.decode('utf-16'))
utf-16 w/ BOM decoded with utf-16    'ABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'
>>> print('utf-16 w/ BOM decoded with utf-16le  %r' % e16.decode('utf-16le'))
utf-16 w/ BOM decoded with utf-16le  '\ufeffABCtestβ貝塔위másbêta|test|اختبار|测试|測試|テスト|परीक्षा|പരിശോധന|פּרובירן|kiểm tra|Ölçek|'

มันคุ้มค่าที่จะรู้ว่ามีเพียงทั้งสองutf-8-sigและutf-16ได้รับกลับสตริงเดิมหลังจากที่ทั้งสองและencodedecode


-3

ปัญหานี้เกิดขึ้นโดยทั่วไปเมื่อคุณบันทึกรหัสหลามของคุณในการเข้ารหัส UTF-8 หรือ UTF-16เพราะหลามเพิ่มอักขระพิเศษบางตัวที่จุดเริ่มต้นของรหัสโดยอัตโนมัติ (ซึ่งไม่ได้แสดงโดยโปรแกรมแก้ไขข้อความ) เพื่อระบุรูปแบบการเข้ารหัส แต่เมื่อคุณพยายามที่จะดำเนินรหัสจะช่วยให้คุณไวยากรณ์ผิดพลาดในบรรทัดที่ 1 คือจุดเริ่มต้นของรหัสเพราะหลามคอมไพเลอร์มีความเข้าใจในการเข้ารหัส ASCII เมื่อคุณดูรหัสของไฟล์โดยใช้การอ่าน ()ฟังก์ชั่นที่คุณสามารถดูที่เริ่มต้นของรหัสกลับ'\ ufeff'จะแสดง ทางออกที่ง่ายที่สุดสำหรับปัญหานี้คือเพียงแค่เปลี่ยนการเข้ารหัสกลับเป็นการเข้ารหัสแบบ ASCII(สำหรับสิ่งนี้คุณสามารถคัดลอกรหัสของคุณไปยัง notepad และบันทึกไว้จำไว้! เลือกการเข้ารหัส ASCII ... หวังว่านี่จะช่วยได้

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