2012-08-08 15 views
5

La forma correcta de cargar texto Unicode de Python 2.7 es algo así como:¿Cómo decodifico unicode una línea a la vez en Python 2.7?

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

(actualización: No, no es ver las respuestas..)

Sin embargo, si el archivo es muy grande, podría querer leer, decodificar y procesar una línea a la vez, de modo que el archivo completo nunca se cargue en la memoria de una vez. Algo así como:

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

iteración El for del aro sobre el gestor de archivo abierto es un generador que lee una línea a la vez.

Esto no funciona, porque si el archivo está codificado utf32, por ejemplo, entonces los bytes en el archivo (en hexadecimal) ser algo como:

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

Y la división en líneas hechas por el bucle for divide en la 0a byte del carácter \n, dando como resultado (en hexadecimal):

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

Así que parte del carácter \n se deja al final de la línea 1, y los tres bytes restantes terminan en línea 2 (seguido de cualquier texto que esté realmente en la línea 2). Llamar al decode en cualquiera de estas líneas resulta comprensible en un UnicodeDecodeError.

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

Así que, obviamente suficiente, la división de un flujo de bytes Unicode en 0a bytes no es la forma correcta para dividirlo en líneas. En su lugar, debería dividir las apariciones del carácter de nueva línea completo de cuatro bytes (0x0a000000). Sin embargo, creo que la forma correcta de detectar estos caracteres es decodificar la secuencia de bytes en una cadena Unicode y buscar los caracteres \n, y esta descodificación de la secuencia completa es exactamente la operación que trato de evitar.

Esto no puede ser un requisito poco común. ¿Cuál es la forma correcta de manejarlo?

+1

¿Intentó leer el archivo utilizando el método codecs.open()? –

+0

@Maulwurfn, ¡no sabía que existía! Pero ahora sí. Gracias. –

Respuesta

1

codecs.open itself notes that io.open is a better option (la nota está justo arriba del objetivo del enlace). No está desaprobado, pero solo porque admite algunos usos esotéricos (bytes-> bytes códecs).

io.open is available in Python 2.6 and higher, y proporciona los mismos comportamientos como de AP3 incorporada open, está mejor optimizado, y no comportarse mal como codecs.open cuando se trata de cosas como las conversiones de fin de línea. La única razón para usar codecs.open es si necesita admitir Python 2.5 y versiones anteriores, de lo contrario, io.open es estrictamente mejor.

import io 

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

Por cierto, puede convertir cualquier ya abierto objeto de fichero binario a un objeto basado en texto de decodificación lisa using io.TextIOWrapper, así que si alguien le ofrece un objeto de tipo fichero existente en modo binario, todavía puede hacer decodificación línea por línea implícitamente 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

intente utilizar el módulo de códecs:

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

Seleccioné la respuesta de @ Simon simplemente porque tiene menos puntos, pero tiene un voto positivo. ¡Gracias! –

+0

¿Eh? ¡Ahora solo tienes un punto! ¡¿¡¿¡Que pasó!?!?! –

7

¿Qué tal intentar somethng como:

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

Creo que esto debería funcionar.

El módulo codecs debe hacer la traducción por usted.

+0

¡Lectores! También vea la respuesta de punto bajo de ShadowRanger cerca de la parte inferior de esta página: "codecs.open docs note que io.open es una mejor opción" ... –

1

Uso codecs.open en lugar de orden interna abierta:

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

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

Por supuesto, he descubierto esta meros momentos después de terminar mi pregunta StackOverflow cuidadosamente elaborado.

+0

@jamylak, gracias por arreglar mi código de mala calidad. –

+0

no hay problema pero solo solucioné la sangría :) – jamylak