2011-01-27 9 views
8

esta línea en mi archivo .py me está dando: "UnicodeDecodeError: códec 'utf8' no puede decodificar bytes en la posición 8-13: gama de códigos Unicode no soportado"escritura cadena UTF-8 dentro de mis archivos pitón

if line.startswith(u"Fußnote"): 

el archivo se guarda en UTF-8 y tiene la codificación en la parte superior: # - - codificación: UTF-8 - -

tengo un montón de otros archivos con UTF-py 8 texto chino codificado en ellos en los comentarios y en las matrices, por ejemplo: arr = [u "texto chino",] así que me pregunto por qué este caso en particular no funciona para mí.

+0

¿Cómo se sabe con certeza que es realmente UTF-8. ¿Puedes mirar la salida apropiada de 'od -t c' en el archivo (si es Unix)? –

+1

También hay 'hexdump -C' en la mayoría de las distribuciones de GNU/Linux y' hd (1) 'en FreeBSD. –

+0

Gracias a todos por las excelentes respuestas, me mudé y estoy lejos de mi caja de Windows en la que estaba trabajando. Me estaba arrancando los pelos por esto, pero creo que finalmente entiendo Unicode. Cuando regrese, aceptaré una respuesta. – Mark

Respuesta

11

Vamos a examinar ese mensaje de error muy de cerca:

"UnicodeDecodeError: 'utf8' codec no puede decodificar bytes en la posición 8-13: gama de códigos Unicode no soportado"

Nota cuidadosamente que dice "bytes en la posición 8-13 "- es una secuencia de 6 bytes UTF-8. Eso podría haber sido válido en las edades oscuras, pero ya que Unicode se congeló en 21 bits, el máximo es de CUATRO bytes. Validación UTF-8 e informe de errores were tightened up recently; como una cuestión de interés, ¿exactamente qué versión de Python está ejecutando?

Con al menos 2.7.1 y 2.6.6, ese error se vuelve más útil "... no se puede decodificar el byte XXXX en la posición 8: byte de inicio no válido" donde XXXX solo puede ser 0xfc o 0xfd si el el mensaje anterior sugería una secuencia de 6 bytes. En ISO-8859-1 o cp1252, 0xfc representa U + 00FC LETRA U MINÚSCULA PEQUEÑA CON DIAESIS (también conocido como u-umlaut, probable sospechoso); 0xfd representa U + 00FD LETRA Y MINÚSCULA LATINA CON AGUDA (menos probable).

El problema NO es con la declaración if line.startswith(u"Fußnote"): en su archivo fuente. Habría recibido un mensaje en la hora de COMPILAR si no era el UTF-8 correcto, y el mensaje habría comenzado con "SyntaxError", no con "UnicodeDecodeError". En cualquier caso, la codificación UTF-8 de esa cadena tiene solo 8 bytes de longitud, no 14.

El problema es (como ha señalado @Mark Tolonen) en cualquier "línea" que se refiera. Solo puede ser un objeto str.

Para obtener más información debe responder a las preguntas de Mark (1) resultado de print repr(line) (2) site.py cambio.

En esta etapa es una buena idea despejar el aire sobre la mezcla de objetos str y unicode (en muchas operaciones, no solo en a.startswith(b)).

A menos que se define la operación para producir un objeto str, no va a coaccionar el objeto unicode a str. Este no es el caso con a.startswith(b). Intentará decodificar el objeto str utilizando la codificación predeterminada (generalmente 'ascii').

Ejemplos:

>>> "\xff".startswith(u"\xab") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0: ordinal not in range(128) 

>>> u"\xff".startswith("\xab") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xab in position 0: ordinal not in range(128) 

Además, No es correcto decir "mezcla y se obtiene UnicodeDecodeError". Es muy posible que el objeto str esté codificado de forma válida en la codificación predeterminada (generalmente 'ascii'): no se genera ninguna excepción.

Ejemplos:

>>> "abc".startswith(u"\xff") 
False 
>>> u"\xff".startswith("abc") 
False 
>>> 
+0

Gracias por la actualización de la mención de Python, y la explicación completa. – Mark

+0

Hola Mark ... gracias por la aceptación del voto popular y la respuesta. Tenga en cuenta que todavía no sabemos qué causó el problema; Sería útil para futuros lectores si respondieran a las 2 preguntas de @ MarkTolonen (edite su pregunta, por favor, no lo haga en un comentario). –

0

Su archivo está guardado en alguna otra codificación, y no UTF-8. Averigua en qué codificación está el archivo (posiblemente CP1252 o menos) y declara eso en su lugar.

2

Sin ver su código, no está claro si el problema es el código o el archivo de datos que está leyendo el código.

Al abrir el archivo, haces:

file = open("essay.txt") 

o:

import codecs 
file = codecs.open("essay.txt", encoding="utf-8") 

lo que hace:

print file.encoding 

dicen si lo añade justo debajo de la línea de open ?

Ambas formas funcionan para mí:

# -- coding: utf-8 -- 

file = open("essay.txt") 

print file.encoding 

for line in file: 
    uline = line.decode("utf-8") 
    print type(uline) 
    if uline.startswith(u"Fußnote"): 
     print "Footnote" 
    else: 
     print "Other" 

y de esta manera:

# -- coding: utf-8 -- 

import codecs 
file = codecs.open("essay.txt", encoding="utf-8") 

print file.encoding 

for line in file: 
    print type(line) 
    if line.startswith(u"Fußnote"): 
     print "Footnote" 
    else: 
     print "Other" 

En la primera, estoy dejando por defecto de Python para abrir el archivo como un flujo de bytes, a continuación, convirtiendo cada línea de una secuencia de bytes a una cadena Unicode usando uline = line.decode("utf-8").

En la segunda, estoy abriendo el archivo como un archivo codificado UTF-8, por lo que Python devuelve cadenas Unicode cuando itero sobre el archivo.


EDITAR

Aquí está una manera trivial que podría utilizar para averiguar si el archivo contiene datos no-UTF8.

import codecs 
file = open("baduni.txt") 
try: 
    for char in codecs.iterdecode(file, "utf-8"): 
     print char 
except UnicodeDecodeError as e: 
    print "error:", e 

Y un ejemplo de ello en uso:

$ echo 'ABC\0200\0101DEF' > baduni.txt 
$ od -c baduni.txt 
0000000 A B C 200 A D E F \n 
0000011 
$ python testuni.py 
error: 'utf8' codec can't decode byte 0x80 in position 3: invalid start byte 

En el ejemplo, el cuarto (contando desde 0 posición 3,) byte es 200 octal/hexadecimal 0x80.
The Wikipedia UTF-8 article muestra que eso solo sería válido como el segundo byte de una secuencia de dos bytes.

6

que puede reproducir el UnicodeDecodeError con este código:

#!/usr/bin/env python 
# -- coding: utf-8 -- 

line='Fußnoteno' 
if line.startswith(u"Fußnote"): 
    print('Hi') 

Tenga en cuenta que line es un objeto de cadena, pero u"Fußnote" es un objeto Unicode. Dado que line es un objeto de cadena, el objeto Unicode se está convirtiendo en un objeto de cadena en la llamada al startswith. En Python2, el valor predeterminado es intentar decodificar usando el códec ascii. Dado que u"ß" no se puede decodificar con el códec ascii, se genera UnicodeDecodeError.

El error puede evitarse si primero hacer line un objeto Unicode:

line='Fußnoteno'.decode('utf-8') 
if line.startswith(u"Fußnote"): 
    print('Hi') 

o si primero hacen u"Fußnote" un objeto de cadena:

line='Fußnoteno' 
if line.startswith(u"Fußnote".encode('utf-8')): 
    print('Hi') 
+0

-1 por 2 razones (1) NO has reproducido ese mensaje de error (inusual), obtendrías la variedad simple (2) el objeto Unicode está ** NO ** convirtiéndose en una cadena [quieres decir 'str' ] objeto en la llamada a startswith. Ver mi respuesta –

3

El error indica línea no es una cadena Unicode. En X.startswith(Y) tanto X como Y deben ser cadenas Unicode o byte. Mezcla y obtienes UnicodeDecodeError. print repr(line) para inspeccionarlo. ¿Has alterado también site.py para cambiar la codificación predeterminada de 'ascii' a 'utf8'? Normalmente es el códec 'ascii' el predeterminado para Python 2.x.