Uso de funciones unicode () y encode () en Python

83

Tengo un problema con la codificación de la variable de ruta y la inserción en la base de datos SQLite . Traté de resolverlo con la función encode ("utf-8") que no ayudó. Luego usé la función unicode () que me da tipo unicode .

print type(path)                  # <type 'unicode'>
path = path.replace("one", "two") # <type 'str'>
path = path.encode("utf-8")       # <type 'str'> strange
path = unicode(path)              # <type 'unicode'>

Finalmente obtuve el tipo Unicode , pero todavía tengo el mismo error que estaba presente cuando el tipo de la variable de ruta era str

sqlite3.ProgrammingError: No debe usar cadenas de bytes de 8 bits a menos que use un text_factory que pueda interpretar cadenas de bytes de 8 bits (como text_factory = str). Se recomienda encarecidamente que, en cambio, cambie su aplicación a cadenas Unicode.

¿Podría ayudarme a solucionar este error y explicar el uso correcto de encode("utf-8")y unicode()funciones? A menudo estoy luchando con eso.

EDITAR:

Esta instrucción execute () generó el error:

cur.execute("update docs set path = :fullFilePath where path = :path", locals())

Olvidé cambiar la codificación de la variable fullFilePath que sufre el mismo problema, pero ahora estoy bastante confundido. ¿Debo usar solo unicode () o encode ("utf-8") o ambos?

No puedo usar

fullFilePath = unicode(fullFilePath.encode("utf-8"))

porque genera este error:

UnicodeDecodeError: el códec 'ascii' no puede decodificar el byte 0xc5 en la posición 32: ordinal no está en el rango (128)

La versión de Python es 2.7.2

xralf
fuente
¿Dónde está el código que genera el error?
newtover
2
Su pregunta exacta ya ha sido respondida: [ stackoverflow.com/questions/2392732/… [1]: stackoverflow.com/questions/2392732/…
garnertb
@newtover Edité la pregunta.
xralf
¿ha convertido ambas variables usadas a unicode?
newtover
2
Aprender cómo Python 3 maneja el texto y los datos realmente me ha ayudado a comprender todo. Entonces es fácil aplicar el conocimiento a Python 2.
Oleh Prypin

Respuestas:

87

Está utilizando encode("utf-8")incorrectamente. Las cadenas de bytes de Python ( strtipo) tienen una codificación, Unicode no. Puede convertir una cadena Unicode en una cadena de bytes de Python usando uni.encode(encoding), y puede convertir una cadena de bytes en una cadena Unicode usando s.decode(encoding)(o equivalentemente, unicode(s, encoding)).

Si fullFilePathy pathson actualmente un strtipo, debería averiguar cómo están codificados. Por ejemplo, si la codificación actual es utf-8, usaría:

path = path.decode('utf-8')
fullFilePath = fullFilePath.decode('utf-8')

Si esto no lo soluciona, el problema real puede ser que no esté usando una cadena Unicode en su execute()llamada, intente cambiarla a lo siguiente:

cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
fuente
Esta declaración fullFilePath = fullFilePath.decode("utf-8")aún genera errores UnicodeEncodeError: 'ascii' codec can't encode characters in position 32-34: ordinal not in range(128). fullFilePath es una combinación de tipo str y string tomada de la columna de texto de la tabla db que debe tener codificación utf-8.
xralf
Según esto pero puede ser UTF-8, UTF-16BE o UTF-16LE. ¿Puedo averiguarlo de alguna manera?
xralf
@xralf, si está combinando diferentes strobjetos, puede estar mezclando codificaciones. ¿Puedes mostrar el resultado de print repr(fullFilePath)?
Andrew Clark
Puedo mostrarlo solo antes de la llamada de decode () . Los caracteres problemáticos son \ u0161 y \ u0165.
xralf
@xralf - ¿Entonces ya es Unicode? Intente cambiar la llamada de ejecución a unicode:cur.execute(u"update docs set path = :fullFilePath where path = :path", locals())
Andrew Clark
121

stres la representación del texto en bytes, unicodees la representación del texto en caracteres.

Decodifica texto de bytes a Unicode y codifica un Unicode en bytes con algo de codificación.

Es decir:

>>> 'abc'.decode('utf-8')  # str to unicode
u'abc'
>>> u'abc'.encode('utf-8') # unicode to str
'abc' 
newtover
fuente
1
Muy buena respuesta, directo al grano. Agregaría que unicodehabla de letras o símbolos, o más genéricamente: runas while strrepresenta una cadena de bytes en una determinada codificación, que debes decode(obviamente en la codificación correcta) para obtener las runas específicas
arainone
Python 3.8 >>'str' object has no attribute 'decode'
Yohan Obadia hace
1

Asegúrese de haber establecido la configuración regional justo antes de ejecutar el script desde el shell, por ejemplo

$ locale -a | grep "^en_.\+UTF-8"
en_GB.UTF-8
en_US.UTF-8
$ export LC_ALL=en_GB.UTF-8
$ export LANG=en_GB.UTF-8

Documentos: man locale, man setlocale.

Kenorb
fuente