2012-01-11 15 views
15

Abbiamo una persona di inserimento dati codificata in UTF-16 su Windows e vorrebbe avere utf-8 e rimuovere il BOM. La conversione utf-8 funziona ma BOM è ancora lì. Come dovrei rimuovere questo? Questo è quello che ho attualmente:conversione utf-16 -> utf-8 E rimuovere BOM

batch_3={'src':'/Users/jt/src','dest':'/Users/jt/dest/'} 
batches=[batch_3] 

for b in batches: 
    s_files=os.listdir(b['src']) 
    for file_name in s_files: 
    ff_name = os.path.join(b['src'], file_name) 
    if (os.path.isfile(ff_name) and ff_name.endswith('.json')): 
     print ff_name 
     target_file_name=os.path.join(b['dest'], file_name) 
     BLOCKSIZE = 1048576 
     with codecs.open(ff_name, "r", "utf-16-le") as source_file: 
     with codecs.open(target_file_name, "w+", "utf-8") as target_file: 
      while True: 
      contents = source_file.read(BLOCKSIZE) 
      if not contents: 
       break 
      target_file.write(contents) 

Se Hexdump -C vedo:

Wed Jan 11$ hexdump -C svy-m-317.json 
00000000 ef bb bf 7b 0d 0a 20 20 20 20 22 6e 61 6d 65 22 |...{.. "name"| 
00000010 3a 22 53 61 76 6f 72 79 20 4d 61 6c 69 62 75 2d |:"Savory Malibu-| 

nel file risultante. Come rimuovere la BOM?

thx

risposta

19

Basta usare str.decode e str.encode:

with open(ff_name, 'rb') as source_file: 
    with open(target_file_name, 'w+b') as dest_file: 
    contents = source_file.read() 
    dest_file.write(contents.decode('utf-16').encode('utf-8')) 

str.decode sarà sbarazzarsi di distinta base per voi (e dedurre l'endianness).

+0

cool - funziona bene, sai come aggiungere un CRLF -> conversione LF facilità nella lettura? thx se puoi aiutare – timpone

+0

Questo approccio (memorizzare l'intero file in memoria due volte) non è molto efficiente, se stai lavorando con file di grandi dimensioni. –

28

Questa è la differenza tra UTF-16LE e UTF-16

  • UTF-16LE è little endian senza una distinta
  • UTF-16 è grande o little endian con un BOM

Quindi, quando si utilizzare UTF-16LE, il BOM è solo una parte del testo. Utilizzare invece UTF-16, in modo che il BOM venga rimosso automaticamente. Il motivo UTF-16LE e UTF-16BE esiste in modo che le persone possano portare in giro il testo "correttamente codificato" senza distinte materiali, che non si applica a te.

Nota cosa accade quando si codifica utilizzando una codifica e decodifica con l'altra. (UTF-16 rileva automaticamente UTF-16LE a volte, non sempre.)

>>> u'Hello, world'.encode('UTF-16LE') 
'H\x00e\x00l\x00l\x00o\x00,\x00 \x00w\x00o\x00r\x00l\x00d\x00' 
>>> u'Hello, world'.encode('UTF-16') 
'\xff\xfeH\x00e\x00l\x00l\x00o\x00,\x00 \x00w\x00o\x00r\x00l\x00d\x00' 
^^^^^^^^ (BOM) 

>>> u'Hello, world'.encode('UTF-16LE').decode('UTF-16') 
u'Hello, world' 
>>> u'Hello, world'.encode('UTF-16').decode('UTF-16LE') 
u'\ufeffHello, world' 
    ^^^^ (BOM) 

o si può fare questo a guscio:

for x in * ; do iconv -f UTF-16 -t UTF-8 <"$x" | dos2unix >"$x.tmp" && mv "$x.tmp" "$x"; done 
Problemi correlati