2012-08-08 17 views
5

Il modo corretto per caricare il testo unicode dal Python 2.7 è qualcosa di simile:Come decodificare unicode una riga alla volta in Python 2.7?

content = open('filename').read().decode('encoding'): 
for line in content.splitlines(): 
    process(line) 

(Aggiornamento: No, non è vedere le risposte..)

Tuttavia, se il file è molto grande, potrei voler leggere, decodificare ed elaborare una riga alla volta, in modo che l'intero file non venga mai caricato in memoria in una sola volta. Qualcosa di simile:

for line in open('filename'): 
    process(line.decode('encoding'))   

iterazione Il for del ciclo sul filehandle aperto è un generatore che legge una riga alla volta.

Questo non funziona, però, perché se il file è codificato UTF-32, per esempio, i byte del file (in esadecimale) cerca qualcosa di simile:

hello\n = 68000000(h) 65000000(e) 6c000000(l) 6c000000(l) 6f000000(o) 0a000000(\n) 

E la divisione in linee fatto da loop for divide sulla 0a byte del carattere \n, con conseguente (in esadecimale):

lines[0] = 0x 68000000 65000000 6c000000 6c000000 6f000000 0a 
lines[1] = 0x 000000 

Così parte del carattere \n è lasciato alla fine della linea 1, e le rimanenti tre byte finire in linea 2 (seguito da qualsiasi testo si trovi effettivamente nella riga 2.) Chiamando decode su una di queste righe si ottiene comprensibilmente un UnicodeDecodeError.

UnicodeDecodeError: 'utf32' codec can't decode byte 0x0a in position 24: truncated data 

Così, abbastanza ovviamente, la suddivisione di un flusso di byte unicode su 0a byte non è il modo corretto di dividerlo in linee. Dovrei invece dividere le occorrenze del carattere di nuova riga a quattro byte (0x0a000000). Tuttavia, penso che il modo corretto per rilevare questi caratteri sia quello di decodificare il flusso di byte in una stringa unicode e cercare i caratteri \n - e questa decodifica dell'intero flusso è esattamente l'operazione che sto cercando di evitare.

Questo non può essere un requisito non comune. Qual è il modo corretto di gestirlo?

+1

Hai provato a leggere il file utilizzando il metodo codecs.open()? –

+0

@ Maulwurfn, non sapevo che esistesse! Ma lo faccio adesso. Grazie. –

risposta

1

codecs.open itself notes that io.open is a better option (la nota è appena sopra l'obiettivo del collegamento). Non è deprecato, ma solo perché supporta alcuni usi esoterici (byte-> byte codec).

io.open is available in Python 2.6 and higher, e fornisce gli stessi comportamenti come di PY3 built-in open, è meglio ottimizzato, e non comportarsi male come codecs.open quando si tratta di cose come le conversioni di linea fine. L'unico motivo per utilizzare codecs.open è se devi supportare Python 2.5 e versioni precedenti, altrimenti, io.open è strettamente migliore.

import io 

# Use with statement for guaranteed, predictable cleanup 
with io.open('filename', encoding='utf-32') as f: 
    for line in f: 
     process(line) 

Per inciso, è possibile convertire qualsiasi già aperto oggetto simile a file binario in un oggetto di testo di decodifica senza soluzione di continuità basato using io.TextIOWrapper, quindi se qualcun altro vi fornisce un oggetto simile a file esistente in modo binario, è ancora possibile decodificare linea per linea implicitamente con:

def process_file(f): 
    if 'b' in f.mode: # Or some better test... 
     f = io.TextIOWrapper(f, encoding='utf-32') 
    for line in f: 
     process(line) 
4

provare a utilizzare il modulo codecs:

for line in codecs.open(filename, encoding='utf32'): 
    do_something(line) 
+0

Ho selezionato la risposta di Simon solo perché ha meno punti, ma ha un upvote. Grazie! –

+0

Eh? Ora hai solo un punto! Quello che è successo!?!?! –

7

ne dite di provare somethng come:

for line in codecs.open("filename", "rt", "utf32"): 
    print line 

Penso che questo dovrebbe funzionare.

Il modulo codecs dovrebbe fare la traduzione per voi.

+0

Lettori! Vedi anche la risposta in basso a ShadowRanger nella parte inferiore di questa pagina: "i documenti codecs.open notano che io.open è un'opzione migliore" ... –

1

Uso codecs.open invece di built-in open:

import codecs 
for line in codecs.open('filename', encoding='encoding'): 
    print repr(line) 

http://docs.python.org/library/codecs.html#codecs.open

Naturalmente, ho scoperto questo pochi istanti dopo aver terminato la mia domanda StackOverflow cura artigianale.

+0

@jamylak, grazie per aver corretto il mio codice scadente. –

+0

nessun problema ma ho solo corretto il rientro :) – jamylak