2011-09-01 7 views
14

Per qualche motivo, Python sembra avere problemi con BOM durante la lettura di stringhe Unicode da un file UTF-8. Considera quanto segue:Perché le stringhe Unicode di Python richiedono un trattamento speciale per BOM UTF-8?

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

Sembra semplice, non è vero?

Questo è quello che ho pensato fino a quando ho eseguito da linea di comando ed ho ottenuto:

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

Una breve visita a Google ha rivelato che BOM deve essere cancellato manualmente:

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

Questo funziona bene Comunque sto lottando per vedere qualche merito in questo.

Esiste una logica dietro al comportamento sopra descritto? Al contrario, UTF-16 funziona perfettamente.

+4

Non può codificarlo perché U + FEFF è un noncharacter non valido. È perché i file UTF-8 * non dovrebbero * contenere un BOM in essi! Non sono né richiesti né raccomandati. L'endianità non ha senso con le unità di codice a 8 bit. Fanno fallire anche le cose, perché non puoi più fare semplicemente 'cat a b c> abc' se quei file hanno delle distinte estranee (leggi: * qualsiasi *) in esse. Gli stream UTF-8 non devono contenere una distinta base. Se è necessario specificare il contenuto del file, si suppone di utilizzare un prototipo di livello superiore. Questo è solo un bug di Windows. – tchrist

+0

@tchrist - Sai, questa spiegazione in combinazione con il suggerimento di Josh Lee sarebbe diventata una risposta perfetta. – Saul

+0

Ok, aggiunto.Spero che funzioni. – tchrist

risposta

28

La codifica 'utf-8-sig' consumerà la firma BOM per conto dell'utente.

+0

Sì, questa è la soluzione ma ero più interessato al perché. – Saul

+3

UTF8 non ha contrassegni di ordine byte per definizione. –

+3

@Gringo Suave: La cosa divertente è che lo standard Unicode consente una distinta componenti in UTF-8. Vedi http://www.unicode.org/versions/Unicode5.0.0/ch02.pdf pagina 36, ​​tabella 2-4. – Saul

13

Hai scritto:

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

Quando si specifica il "utf-8" codifica in Python, che vi porta in parola. I file UTF-8 non devono contenere per contenere un BOM. Non sono né richiesti né raccomandati. L'endianità non ha senso con le unità di codice a 8 bit.

distinte base rovinare tutto, troppo, perché non è più possibile fare solo:

$ cat a b c > abc 

se quei file UTF-8 hanno estranea (leggi: eventuali) distinte base in loro. Scopri ora perché le BOM sono così stupide/cattive/dannose in UTF-8? In realtà rompono le cose.

Una distinta base è metadata, non dati, e le specifiche di codifica UTF-8 non ne consentono il funzionamento delle specifiche UTF-16 e UTF-32. Quindi Python ti ha preso in parola e ha seguito le specifiche. Difficile dare la colpa a quello.

Se si sta tentando di utilizzare la distinta materiali come numero magico di tipo file per specificare il contenuto del file, non si dovrebbe farlo. Dovresti davvero usare un prototipo di livello superiore per questi scopi di metadati, proprio come faresti con un tipo MIME.

Questo è solo un altro bug bug di Windows, la soluzione per cui è utilizzare la codifica alternativa "utf-8-sig" da passare a Python.

+2

Se possibile, puoi codificare U + FEFF in UTF-8. Non puoi codificarlo in latin-1, che è quello che 'charmap' usa per me. –

+2

@Josh: hai ragione. Continuo a disfunzioni dylexic e lettura FEFF come FFFE. È FFFE illegale per gli scambi aperti. FEFF è semplicemente "ZERO WIDTH NO-BREAK SPACE". – tchrist

+2

È molto frustrante occuparsi di questi e mi piacerebbe chiamarlo un bug di Windows, ma lo standard effettivamente consente BOM nei file UTF-8. Vedere http://unicode.org/versions/Unicode5.0.0/ch02.pdf pagina 36, ​​tabella 2-4 e il testo "_ [a BOM] può essere essere incontrato in contesti in cui i dati UTF-8 vengono convertiti da un'altra codifica forme che utilizzano una BOM o in cui il BOM viene utilizzato come firma UTF-8. "e http://en.wikipedia.org/wiki/Byte_order_mark e [Re: pre-HTML5 e il BOM da Asmus Freytag nel 2012 -07-13 (Unicode Mail List Archive)] (http://www.unicode.org/mail-arch/unicode-ml/y2012-m07/0268.html) – nealmcb

Problemi correlati