2011-09-01 2 views
14

Z jakiegoś powodu wydaje się, że Python ma problemy z BOM podczas odczytywania ciągów Unicode z pliku UTF-8. Rozważ następujące:Dlaczego łańcuchy Unicode w języku Python wymagają specjalnego traktowania dla pliku specyfikacji UTF-8?

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

Wydaje się proste, prawda?

To co myślałem, aż wpadłem go z linii poleceń i otrzymał:

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

krótkie nawiedzenie Google ujawniło, że BOM musi być usuwane ręcznie:

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

To jeden działa dobrze. Jednak staram się dostrzec w tym jakąś zasługę.

Czy istnieje uzasadnienie powyżej opisanych zachowań? W przeciwieństwie do UTF-16 działa płynnie.

+4

Nie można go zakodować, ponieważ U + FEFF jest nieprawidłowym noncharacter. Dzieje się tak dlatego, że pliki UTF-8 * nie powinny zawierać w nich LM! Nie są one wymagane ani zalecane. Endianness nie ma sensu z 8-bitowymi jednostkami kodu. Oni też to robią, bo nie można już po prostu zrobić "cat a b c> abc", jeśli pliki te zawierają nieistniejące (czytaj: * any *) BOMy w nich. Strumienie UTF-8 nie powinny zawierać LM. Jeśli chcesz określić zawartość pliku, powinieneś użyć prototocl wyższego poziomu. To tylko błąd systemu Windows. – tchrist

+0

@tchrist - Wiesz, to wyjaśnienie w połączeniu z sugestią Josha Lee stałoby się idealną odpowiedzią. – Saul

+0

OK, dodano.Mam nadzieję, że działa. – tchrist

Odpowiedz

28

Kodowanie 'utf-8-sig' pochłonie podpis BOM w Twoim imieniu.

+0

Tak, to jest poprawka, ale byłem bardziej zainteresowany dlaczego. – Saul

+3

UTF8 nie ma znaku kolejności bajtów z definicji. –

+3

@Gringo Suave: Zabawne jest to, że standard Unicode pozwala na zestawienie BOM w UTF-8. Zobacz http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf strona 36, ​​tabela 2-4. – Saul

13

Napisałeś:

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

Po określić kodowanie w Pythonie "utf-8", zabiera cię za słowo. Pliki UTF-8 nie powinny zawierać zawierających w nich LM. Nie są one wymagane ani zalecane. Endianness nie ma sensu z 8-bitowymi jednostkami kodu.

LM śruba rzeczy, też, bo nie można już po prostu zrobić:

$ cat a b c > abc 

jeśli te UTF-8 pliki mają obce (czytaj: dowolny) LM w nich. Zobacz teraz, dlaczego LM są tak głupie/złe/szkodliwe w UTF-8? W rzeczywistości łamią rzeczy.

Zestawienie komponentów to metadane, a nie dane, a specyfikacja kodowania UTF-8 nie uwzględnia ich w sposób określony w specyfikacjach UTF-16 i UTF-32. Tak więc Python zabrał cię na słowo i podążał za specyfikacją. Trudno to za to winić.

Jeśli próbujesz użyć BOM jako magicznej liczby typów plików, aby określić zawartość pliku, naprawdę nie powinieneś tego robić. Naprawdę powinieneś używać prototocl wyższego poziomu do tych celów metadanych, tak jak w przypadku typu MIME.

To kolejny błędny błąd systemu Windows, którego obejście polega na użyciu alternatywnego kodowania "utf-8-sig" w celu przekazania do Pythona.

+2

Możesz kodować U + FEFF do UTF-8, jeśli chcesz. Nie możesz zakodować go na łaciński-1, co jest dla mnie "urokiem". –

+2

@ Jos: Masz rację. Wciąż dostaję się wadliwe działanie dylektyki i odczytuję FEFF jako FFFE. To FFFE jest nielegalne przy otwartej wymianie. FEFF to po prostu "ZERO WIDTH NO-BREAK SPACE". – tchrist

+2

To jest bardzo frustrujące, aby sobie z nimi poradzić i bardzo chciałbym nazwać to błędem Windows, ale standard rzeczywiście dopuszcza BOM-y w plikach UTF-8. Zobacz http://unicode.org/versions/Unicode5.0.0/ch02.pdf strona 36, ​​tabela 2-4, a tekst "_ [a BOM] może być napotkany w kontekstach, w których dane UTF-8 są konwertowane z innego kodowania formularze, które używają zestawu BOM lub zestawienia BOM jako podpisu UTF-8. "i http://en.wikipedia.org/wiki/Byte_order_mark oraz [Re: pre-HTML5 i BOM z Asmus Freytag w 2012 r. -07-13 (Unicode Mail List Archive)] (http://www.unicode.org/mail-arch/unicode-ml/y2012-m07/0268.html) – nealmcb