@Johnsyweb Debido a{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
alex
Respuestas:
295
En Python 3, todas las cadenas son secuencias de caracteres Unicode. Hay un bytestipo que contiene bytes sin procesar.
En Python 2, una cadena puede ser de tipo stro de tipo unicode. Puedes decir qué código usando algo como esto:
def whatisthis(s):if isinstance(s, str):print"ordinary string"elif isinstance(s, unicode):print"unicode string"else:print"not a string"
Esto no distingue "Unicode o ASCII"; solo distingue los tipos de Python. Una cadena Unicode puede consistir en puramente caracteres en el rango ASCII, y una cadena de bytes puede contener ASCII, Unicode codificado o incluso datos no textuales.
En Python 2, stres solo una secuencia de bytes. Python no sabe cuál es su codificación. El unicodetipo es la forma más segura de almacenar texto. Si quieres entender esto más, te recomiendo http://farmdev.com/talks/unicode/ .
En Python 3, stres como Python 2 unicodey se usa para almacenar texto. Lo que se llamó stren Python 2 se llama bytesen Python 3.
Cómo saber si una cadena de bytes es válida utf-8 o ascii
Puede llamar decode. Si genera una excepción UnicodeDecodeError, no fue válida.
>>> u_umlaut = b'\xc3\x9c'# UTF-8 representation of the letter 'Ü'>>> u_umlaut.decode('utf-8')
u'\xdc'>>> u_umlaut.decode('ascii')Traceback(most recent call last):File"<stdin>", line 1,in<module>UnicodeDecodeError:'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Solo para referencia de otras personas: str.decode no existe en python 3. Parece que tienes que hacerlo unicode(s, "ascii")o algo así
Shadow
3
Lo siento, quise decirstr(s, "ascii")
Sombra
1
Esto no es exacto para python 3
ProsperousHeart
2
@ProsperousHeart Actualizado para cubrir Python 3. Y para tratar de explicar la diferencia entre cadenas de bytes y cadenas unicode.
Mikel
44
En python 3.x todas las cadenas son secuencias de caracteres Unicode. y hacer la verificación isinstance para str (que significa cadena unicode por defecto) debería ser suficiente.
isinstance(x, str)
Con respecto a python 2.x, la mayoría de las personas parecen estar usando una declaración if que tiene dos verificaciones. uno para str y otro para unicode.
Sin embargo, si desea verificar si tiene un objeto 'tipo cadena' con una sola declaración, puede hacer lo siguiente:
Esto es falso En Python 2.7 isinstance(u"x",basestring)regresa True.
PythonNut
11
@PythonNut: Creo que ese era el punto. El uso de isinstance (x, basetring) es suficiente para reemplazar las distintas pruebas duales anteriores.
KQ.
55
Es útil en muchos casos, pero evidentemente no es lo que quiso decir el interrogador.
mhsmith
3
Esta es la respuesta a la pregunta. Todos los demás entendieron mal lo que OP dijo y dieron respuestas genéricas sobre la verificación de tipos en Python.
fiatjaf
1
No responde la pregunta de OP. El título de la pregunta (solo) PODRÍA interpretarse de manera que esta respuesta sea correcta. Sin embargo, OP dice específicamente "averiguar qué" en la descripción de la pregunta, y esta respuesta no aborda eso.
MD004
31
Unicode no es una codificación, para citar a Kumar McMillan:
Si ASCII, UTF-8 y otras cadenas de bytes son "texto" ...
Esas diapositivas son probablemente la mejor introducción a Unicode que he encontrado hasta la fecha
Jonny
23
Si su código necesita ser compatible tanto con Python 2 como con Python 3, no puede usar directamente cosas como isinstance(s,bytes)o isinstance(s,unicode)sin envolverlas en try / except o una prueba de versión de python, porquebytes no está definido en Python 2 yunicode no está definido en Python 3 .
Hay algunas soluciones feas. Una muy fea es comparar el nombre del tipo, en lugar de comparar el tipo en sí. Aquí hay un ejemplo:
# convert bytes (python 3) or unicode (python 2) to strif str(type(s))=="<class 'bytes'>":# only possible in Python 3
s = s.decode('ascii')# or s = str(s)[2:-1]elif str(type(s))=="<type 'unicode'>":# only possible in Python 2
s = str(s)
Una solución alternativa un poco menos fea es verificar el número de versión de Python, por ejemplo:
if sys.version_info >=(3,0,0):# for Python 3if isinstance(s, bytes):
s = s.decode('ascii')# or s = str(s)[2:-1]else:# for Python 2if isinstance(s, unicode):
s = str(s)
Ambas son poco pitónicas, y la mayoría de las veces probablemente haya una mejor manera.
La mejor manera es probablemente usar six, y probar contra six.binary_typeysix.text_type
Ian Clelland
1
Puede usar los tipos .__ nombre__ para sondear nombres de tipos.
Paulo Freitas
No estoy muy seguro del caso de uso de ese bit de código, a menos que haya un error lógico. Creo que debería haber un "no" en el código de Python 2. De lo contrario, ¡está convirtiendo todo en cadenas unicode para Python 3 y lo contrario para Python 2!
oligofren
Sí, oligofren, eso es lo que hace. Las cadenas internas estándar son Unicode en Python 3 y ASCII en Python 2. Por lo tanto, los fragmentos de código convierten el texto al tipo de cadena interna estándar (ya sea Unicode o ASCII).
Dave Burton el
12
utilizar:
import six
if isinstance(obj, six.text_type)
dentro de las seis bibliotecas se representa como:
if PY3:
string_types = str,else:
string_types = basestring,
debería ser if isinstance(obj, six.text_type) . Pero sí, esta es la respuesta correcta.
karantan
No responde la pregunta de OP. El título de la pregunta (solo) PODRÍA interpretarse de manera que esta respuesta sea correcta. Sin embargo, OP dice específicamente "averiguar qué" en la descripción de la pregunta, y esta respuesta no aborda eso.
MD004
4
Tenga en cuenta que en Python 3, no es realmente justo decir nada de:
strs son UTFx para cualquier x (por ejemplo, UTF8)
strs son Unicode
strs son colecciones ordenadas de caracteres Unicode
El strtipo de Python es (normalmente) una secuencia de puntos de código Unicode, algunos de los cuales se asignan a caracteres.
Incluso en Python 3, no es tan simple responder esta pregunta como te puedas imaginar.
Una forma obvia de probar cadenas compatibles con ASCII es mediante un intento de codificación:
"Hello there!".encode("ascii")#>>> b'Hello there!'"Hello there... ☃!".encode("ascii")#>>> Traceback (most recent call last):#>>> File "", line 4, in <module>#>>> UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 15: ordinal not in range(128)
El error distingue los casos.
En Python 3, incluso hay algunas cadenas que contienen puntos de código Unicode no válidos:
"Hello there!".encode("utf8")#>>> b'Hello there!'"\udcc3".encode("utf8")#>>> Traceback (most recent call last):#>>> File "", line 19, in <module>#>>> UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 0: surrogates not allowed
Esto puede ayudar a alguien más, comencé a probar el tipo de cadena de la variable s, pero para mi aplicación, tenía más sentido simplemente devolver s como utf-8. El proceso que llama a return_utf, luego sabe de qué se trata y puede manejar la cadena de manera apropiada. El código no es prístino, pero tengo la intención de que sea independiente de la versión de Python sin una prueba de versión o importando seis. Comente con las mejoras al código de muestra a continuación para ayudar a otras personas.
def return_utf(s):if isinstance(s, str):return s.encode('utf-8')if isinstance(s,(int, float, complex)):return str(s).encode('utf-8')try:return s.encode('utf-8')exceptTypeError:try:return str(s).encode('utf-8')exceptAttributeError:return s
exceptAttributeError:return s
return s # assume it was already utf-8
¡Tú, mi amigo, mereces ser la respuesta correcta! ¡Estoy usando Python 3 y todavía tenía problemas hasta que encontré este tesoro!
mnsr
2
Podría usar el Detector de codificación universal , pero tenga en cuenta que solo le dará una mejor suposición, no la codificación real, porque es imposible saber la codificación de una cadena "abc", por ejemplo. Necesitará obtener información de codificación en otro lugar, por ejemplo, el protocolo HTTP utiliza el encabezado Content-Type para eso.
Un enfoque simple es verificar si unicodees una función incorporada. Si es así, estás en Python 2 y tu cadena será una cadena. Para asegurarse de que todo está en unicodeuno, puede hacer:
import builtins
i ='cats'if'unicode'in dir(builtins):# True in python 2, False in 3
i = unicode(i)
{UnicodeDecodeError} 'ascii' codec can't decode byte 0xc2
Respuestas:
En Python 3, todas las cadenas son secuencias de caracteres Unicode. Hay un
bytes
tipo que contiene bytes sin procesar.En Python 2, una cadena puede ser de tipo
str
o de tipounicode
. Puedes decir qué código usando algo como esto:Esto no distingue "Unicode o ASCII"; solo distingue los tipos de Python. Una cadena Unicode puede consistir en puramente caracteres en el rango ASCII, y una cadena de bytes puede contener ASCII, Unicode codificado o incluso datos no textuales.
fuente
Cómo saber si un objeto es una cadena Unicode o una cadena de bytes
Puedes usar
type
oisinstance
.En Python 2:
En Python 2,
str
es solo una secuencia de bytes. Python no sabe cuál es su codificación. Elunicode
tipo es la forma más segura de almacenar texto. Si quieres entender esto más, te recomiendo http://farmdev.com/talks/unicode/ .En Python 3:
En Python 3,
str
es como Python 2unicode
y se usa para almacenar texto. Lo que se llamóstr
en Python 2 se llamabytes
en Python 3.Cómo saber si una cadena de bytes es válida utf-8 o ascii
Puede llamar
decode
. Si genera una excepción UnicodeDecodeError, no fue válida.fuente
unicode(s, "ascii")
o algo asístr(s, "ascii")
En python 3.x todas las cadenas son secuencias de caracteres Unicode. y hacer la verificación isinstance para str (que significa cadena unicode por defecto) debería ser suficiente.
Con respecto a python 2.x, la mayoría de las personas parecen estar usando una declaración if que tiene dos verificaciones. uno para str y otro para unicode.
Sin embargo, si desea verificar si tiene un objeto 'tipo cadena' con una sola declaración, puede hacer lo siguiente:
fuente
isinstance(u"x",basestring)
regresaTrue
.Unicode no es una codificación, para citar a Kumar McMillan:
Lea el Unicode In Python de McMillan , una charla completamente desmitificada de PyCon 2008, que explica las cosas mucho mejor que la mayoría de las respuestas relacionadas en Stack Overflow.
fuente
Si su código necesita ser compatible tanto con Python 2 como con Python 3, no puede usar directamente cosas como
isinstance(s,bytes)
oisinstance(s,unicode)
sin envolverlas en try / except o una prueba de versión de python, porquebytes
no está definido en Python 2 yunicode
no está definido en Python 3 .Hay algunas soluciones feas. Una muy fea es comparar el nombre del tipo, en lugar de comparar el tipo en sí. Aquí hay un ejemplo:
Una solución alternativa un poco menos fea es verificar el número de versión de Python, por ejemplo:
Ambas son poco pitónicas, y la mayoría de las veces probablemente haya una mejor manera.
fuente
six
, y probar contrasix.binary_type
ysix.text_type
utilizar:
dentro de las seis bibliotecas se representa como:
fuente
if isinstance(obj, six.text_type)
. Pero sí, esta es la respuesta correcta.Tenga en cuenta que en Python 3, no es realmente justo decir nada de:
str
s son UTFx para cualquier x (por ejemplo, UTF8)str
s son Unicodestr
s son colecciones ordenadas de caracteres UnicodeEl
str
tipo de Python es (normalmente) una secuencia de puntos de código Unicode, algunos de los cuales se asignan a caracteres.Incluso en Python 3, no es tan simple responder esta pregunta como te puedas imaginar.
Una forma obvia de probar cadenas compatibles con ASCII es mediante un intento de codificación:
El error distingue los casos.
En Python 3, incluso hay algunas cadenas que contienen puntos de código Unicode no válidos:
Se utiliza el mismo método para distinguirlos.
fuente
Esto puede ayudar a alguien más, comencé a probar el tipo de cadena de la variable s, pero para mi aplicación, tenía más sentido simplemente devolver s como utf-8. El proceso que llama a return_utf, luego sabe de qué se trata y puede manejar la cadena de manera apropiada. El código no es prístino, pero tengo la intención de que sea independiente de la versión de Python sin una prueba de versión o importando seis. Comente con las mejoras al código de muestra a continuación para ayudar a otras personas.
fuente
Podría usar el Detector de codificación universal , pero tenga en cuenta que solo le dará una mejor suposición, no la codificación real, porque es imposible saber la codificación de una cadena "abc", por ejemplo. Necesitará obtener información de codificación en otro lugar, por ejemplo, el protocolo HTTP utiliza el encabezado Content-Type para eso.
fuente
Para compatibilidad con py2 / py3 simplemente use
import six if isinstance(obj, six.text_type)
fuente
Un enfoque simple es verificar si
unicode
es una función incorporada. Si es así, estás en Python 2 y tu cadena será una cadena. Para asegurarse de que todo está enunicode
uno, puede hacer:fuente