2011-09-01 29 views
14

Vì một lý do nào đó, Python có vẻ đang gặp sự cố với BOM khi đọc chuỗi unicode từ tệp UTF-8. Hãy xem xét những điều sau:Tại sao chuỗi unicode Python yêu cầu xử lý đặc biệt cho UTF-8 BOM?

with open('test.py') as f: 
    for line in f: 
     print unicode(line, 'utf-8') 

Có vẻ đơn giản, phải không?

Đó là những gì tôi nghĩ đến khi tôi chạy nó từ dòng lệnh và nhận được:

UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined>

Một thăm viếng ngắn gọn để Google tiết lộ rằng BOM phải được xóa bằng tay:

import codecs 
with open('test.py') as f: 
    for line in f: 
     print unicode(line.replace(codecs.BOM_UTF8, ''), 'utf-8') 

Cái này chạy tốt. Tuy nhiên tôi đang đấu tranh để xem bất kỳ công đức trong này.

Có lý do nào đằng sau hành vi được mô tả ở trên không? Ngược lại, UTF-16 hoạt động liền mạch.

+4

Nó không thể mã hóa nó vì U + FEFF là một noncharacter không hợp lệ. Đó là vì các tệp UTF-8 * không được cho phép * chứa BOM trong đó! Chúng không bắt buộc và cũng không được khuyến cáo. Endianness không có ý nghĩa với các đơn vị mã 8-bit. Chúng cũng vặn vẹo mọi thứ, bởi vì bạn không còn có thể làm 'cat a b c> abc' nếu những tập tin đó không liên quan (đọc: * bất kỳ *) BOM trong chúng. Dòng UTF-8 không được chứa BOM. Nếu bạn cần phải xác định nội dung của tập tin, bạn có nghĩa vụ phải sử dụng một prototocl cấp cao hơn. Đây chỉ là một lỗi Windows. – tchrist

+0

@tchrist - Bạn biết đấy, lời giải thích này kết hợp với lời đề nghị của Josh Lee sẽ trở thành một câu trả lời hoàn hảo. – Saul

+0

Ok, đã thêm.Hy vọng rằng công trình. – tchrist

Trả lời

28

Mã hóa 'utf-8-sig' sẽ sử dụng chữ ký BOM thay cho bạn.

+0

Vâng, đó là bản sửa lỗi nhưng tôi quan tâm nhiều hơn đến lý do tại sao. – Saul

+3

UTF8 không có dấu thứ tự byte theo định nghĩa. –

+3

@Gringo Suave: Điều thú vị là chuẩn Unicode cho phép BOM trong UTF-8. Xem http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf trang 36, bảng 2-4. – Saul

13

Bạn đã viết:

UnicodeEncodeError: 'charmap' codec can't encode character u'\ufeff' in position 0: character maps to <undefined> 

Khi bạn xác định mã hóa "utf-8" bằng Python, nó sẽ đưa bạn vào văn bản của bạn. Tệp UTF-8 không được coi là để chứa BOM trong đó. Chúng không bắt buộc và cũng không được khuyến cáo. Endianness không có ý nghĩa với các đơn vị mã 8-bit.

BOMs vít mọi thứ lên, quá, vì bạn có thể không còn chỉ làm:

$ cat a b c > abc 

nếu những file UTF-8 có không liên quan (đọc: có) BOMs trong đó. Xem tại sao các BOM quá ngu ngốc/xấu/có hại trong UTF-8? Họ thực sự phá vỡ mọi thứ.

BOM là siêu dữ liệu, không phải dữ liệu và thông số mã hóa UTF-8 không cho phép chúng theo cách các thông số UTF-16 và UTF-32 thực hiện. Vì vậy, Python đã đưa bạn vào từ của bạn và theo thông số kỹ thuật. Khó để đổ lỗi cho điều đó.

Nếu bạn đang cố gắng sử dụng BOM làm số ma thuật để xác định nội dung của tệp, bạn thực sự không nên làm điều đó. Bạn thực sự phải sử dụng prototocl mức cao hơn cho các mục đích siêu dữ liệu này, giống như bạn làm với loại MIME.

Đây chỉ là một lỗi Windows khác, giải pháp thay thế là sử dụng mã hóa thay thế "utf-8-sig" để chuyển sang Python.

+2

Bạn có thể mã hóa U + FEFF thành UTF-8 nếu muốn. Bạn không thể mã hóa nó thành latin-1, đó là những gì 'charmap' sử dụng cho tôi. –

+2

@Josh: Bạn nói đúng. Tôi tiếp tục gặp trục trặc dylexic và đọc FEFF như FFFE. Đó là FFFE bất hợp pháp cho giao lộ mở. FEFF chỉ là 'KHÔNG GIAN KHÔNG GIAN KHÔNG GIAN '. – tchrist

+2

Rất bực bội khi xử lý những lỗi này, và tôi rất muốn gọi đây là lỗi Windows, nhưng tiêu chuẩn thực sự cho phép BOM trong tệp UTF-8. Xem http://unicode.org/versions/Unicode5.0.0/ch02.pdf trang 36, bảng 2-4 và văn bản "_ [a BOM] có thể gặp phải trong ngữ cảnh nơi dữ liệu UTF-8 được chuyển đổi từ mã hóa khác các biểu mẫu sử dụng BOM hoặc nơi BOM được sử dụng làm chữ ký UTF-8._ "và http://en.wikipedia.org/wiki/Byte_order_mark và [Re: pre-HTML5 và BOM từ Asmus Freytag vào năm 2012 -07-13 (Lưu trữ Danh sách Thư Unicode)] (http://www.unicode.org/mail-arch/unicode-ml/y2012-m07/0268.html) – nealmcb

Các vấn đề liên quan