Trabajando con Python 2.7, me pregunto qué ventaja real hay en usar el tipo en unicode
lugar de str
, ya que ambos parecen poder contener cadenas Unicode. ¿Hay alguna razón especial además de poder establecer códigos Unicode en unicode
cadenas usando el carácter de escape \
?:
Ejecutando un módulo con:
# -*- coding: utf-8 -*-
a = 'á'
ua = u'á'
print a, ua
Resultados en: á, á
EDITAR:
Más pruebas con el shell de Python:
>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'
Entonces, la unicode
cadena parece estar codificada usando en latin1
lugar de utf-8
y la cadena sin procesar está codificada usando utf-8
? ¡Estoy aún más confundido ahora! : S
unicode
, es sólo una abstracción de caracteres Unicode;unicode
se puede convertirstr
con alguna codificación (por ejemploutf-8
).Respuestas:
unicode
está destinado a manejar texto . El texto es una secuencia de puntos de código que puede ser más grande que un solo byte . El texto se puede codificar en una codificación específica para representar el texto como bytes sin formato (por ejemploutf-8
,latin-1
...).¡Tenga en cuenta que
unicode
no está codificado ! La representación interna utilizada por Python es un detalle de implementación, y no debería preocuparse por ella siempre que pueda representar los puntos de código que desea.Por el contrario,
str
en Python 2 es una secuencia simple de bytes . ¡No representa texto!Puede pensar
unicode
en una representación general de un texto, que se puede codificar de muchas formas diferentes en una secuencia de datos binarios representados mediantestr
.Nota: En Python 3,
unicode
se cambió el nombre astr
y hay un nuevobytes
tipo para una secuencia simple de bytes.Algunas diferencias que puedes ver:
Tenga en cuenta que al usar
str
tiene un control de nivel inferior en los bytes individuales de una representación de codificación específica, mientras que al usarunicode
solo puede controlar en el nivel de punto de código. Por ejemplo, puede hacer:Lo que antes era válido UTF-8, ya no lo es. Al usar una cadena Unicode, no puede operar de tal manera que la cadena resultante no sea un texto Unicode válido. Puede eliminar un punto de código, reemplazar un punto de código con un punto de código diferente, etc. pero no puede meterse con la representación interna.
fuente
unicode
objetos, supongo que primero tenemos que explícitamenteencode()
en el formato de codificación adecuado, ya que no sabemos cuál se está utilizando internamente para representar elunicode
valor.unicode
objeto.unicode
no está codificada es completamente incorrecta. UTF-16 / UCS-2 y UTF-32 / UCS-4 también son codificaciones ... y en el futuro posiblemente se creen más de estas. El punto es que el hecho de que no debería preocuparse por los detalles de la implementación (¡y, de hecho, no debería!), Todavía no significa queunicode
no esté codificado. Por supuesto que lo es. Si puede ser.decode()
o no es una historia completamente diferente.unicode
representación interna del objeto puede ser lo que quiera, incluida una no estándar. En particular, en python3 +unicode
qué utilizar una representación interna no estándar que también cambia en función de los datos contenidos. Como tal, no es una codificación estándar . Unicode como estándar de texto solo define puntos de código que son una representación abstracta de texto, hay muchas formas de codificar unicode en la memoria, incluido el utf-X estándar, etc. Python usa su propia forma de eficiencia.unicode
objeto de CPython , ya que no usa UTF-16, ni UTF-32. Utiliza una representación ad hoc, y si desea codificar los datos en bytes reales, debe usarlosencode
. Además: el lenguaje no exige cómounicode
se implementa, por lo que diferentes versiones o implementaciones de Python pueden (y tienen ) una representación interna diferente.Unicode y las codificaciones son cosas completamente diferentes y no relacionadas.
Unicode
Asigna una identificación numérica a cada carácter:
Entonces, Unicode asigna el número 0x41 a A, 0xE1 a á y 0x414 a Д.
Incluso la pequeña flecha → que utilicé tiene su número Unicode, es 0x2192. E incluso los emojis tienen sus números Unicode, 😂 es 0x1F602.
Puede buscar los números Unicode de todos los caracteres en esta tabla . En particular, puede encontrar los primeros tres caracteres arriba aquí , la flecha aquí y el emoji aquí .
Estos números asignados a todos los caracteres por Unicode se denominan puntos de código .
El propósito de todo esto es proporcionar un medio para hacer referencia inequívoca a cada carácter. Por ejemplo, si estoy hablando de 😂, en lugar de decir "ya sabes, este emoji riendo con lágrimas" , solo puedo decir, punto de código Unicode 0x1F602 . Más fácil, ¿verdad?
Tenga en cuenta que los puntos de código Unicode generalmente se formatean con un principio
U+
, luego el valor numérico hexadecimal se completa con al menos 4 dígitos. Entonces, los ejemplos anteriores serían U + 0041, U + 00E1, U + 0414, U + 2192, U + 1F602.Los puntos de código Unicode van desde U + 0000 a U + 10FFFF. Eso es 1,114,112 números. 2048 de estos números se utilizan para sustitutos , por lo que quedan 1,112,064. Esto significa que Unicode puede asignar un ID único (punto de código) a 1,112,064 caracteres distintos. Aún no todos estos puntos de código están asignados a un carácter y Unicode se extiende continuamente (por ejemplo, cuando se introducen nuevos emojis).
Lo importante a recordar es que todo lo que hace Unicode es asignar un ID numérico, llamado punto de código, a cada carácter para una referencia fácil y sin ambigüedades.
Codificaciones
Asignar caracteres a patrones de bits.
Estos patrones de bits se utilizan para representar los caracteres en la memoria de la computadora o en el disco.
Hay muchas codificaciones diferentes que cubren diferentes subconjuntos de caracteres. En el mundo de habla inglesa, las codificaciones más comunes son las siguientes:
ASCII
Asigna 128 caracteres (puntos de código U + 0000 a U + 007F) a patrones de bits de longitud 7.
Ejemplo:
Puede ver todas las asignaciones en esta tabla .
ISO 8859-1 (también conocido como Latin-1)
Asigna 191 caracteres (puntos de código U + 0020 a U + 007E y U + 00A0 a U + 00FF) a patrones de bits de longitud 8.
Ejemplo:
Puede ver todas las asignaciones en esta tabla .
UTF-8
Mapas 1,112,064 caracteres (todos los puntos de código Unicode existentes) a patrones de bits de cualquiera de longitud 8, 16, 24, o 32 bits (es decir, 1, 2, 3, o 4 bytes).
Ejemplo:
La forma en que UTF-8 codifica caracteres en cadenas de bits se describe muy bien aquí .
Unicode y codificaciones
Al observar los ejemplos anteriores, queda claro cómo es útil Unicode.
Por ejemplo, si soy Latin-1 y quiero explicar mi codificación de á, no necesito decir:
Pero solo puedo decir:
Y si soy UTF-8 , puedo decir:
Y es inequívocamente claro para todos a qué personaje nos referimos.
Ahora a la confusión que a menudo surge
Es cierto que a veces el patrón de bits de una codificación, si lo interpreta como un número binario, es el mismo que el punto de código Unicode de este carácter.
Por ejemplo:
Por supuesto, esto se ha organizado así a propósito para mayor comodidad. Pero deberías verlo como una pura coincidencia . El patrón de bits utilizado para representar un carácter en la memoria no está vinculado de ninguna manera al punto de código Unicode de este carácter.
Nadie incluso dice que tienes que interpretar una cadena de bits como 11100001 como un número binario. Míralo como la secuencia de bits que Latin-1 usa para codificar el carácter á .
De vuelta a tu pregunta
La codificación que usa su intérprete de Python es UTF-8 .
Esto es lo que sucede en sus ejemplos:
Ejemplo 1
Lo siguiente codifica el carácter á en UTF-8. Esto da como resultado la cadena de bits 11000011 10100001, que se guarda en la variable
a
.Cuando observa el valor de
a
, su contenido 11000011 10100001 tiene el formato del número hexadecimal 0xC3 0xA1 y se genera como'\xc3\xa1'
:Ejemplo 2
Lo siguiente guarda el punto de código Unicode de á, que es U + 00E1, en la variable
ua
(no sabemos qué formato de datos usa Python internamente para representar el punto de código U + 00E1 en la memoria, y no es importante para nosotros):Cuando observa el valor de
ua
, Python le dice que contiene el punto de código U + 00E1:Ejemplo 3
Lo siguiente codifica el punto de código Unicode U + 00E1 (que representa el carácter á) con UTF-8, lo que da como resultado el patrón de bits 11000011 10100001. Nuevamente, para la salida, este patrón de bits se representa como el número hexadecimal 0xC3 0xA1:
Ejemplo 4
Lo siguiente codifica el punto de código Unicode U + 00E1 (que representa el carácter á) con Latin-1, lo que da como resultado el patrón de bits 11100001. Para la salida, este patrón de bits se representa como el número hexadecimal 0xE1, que por coincidencia es el mismo que el inicial punto de código U + 00E1:
No hay relación entre el objeto Unicode
ua
y la codificación Latin-1. Que el punto de código de á sea U + 00E1 y la codificación Latin-1 de á sea 0xE1 (si interpreta el patrón de bits de la codificación como un número binario) es una pura coincidencia.fuente
Su terminal está configurado para UTF-8.
El hecho de que la imprenta
a
funcione es una coincidencia; está escribiendo bytes UTF-8 sin procesar en el terminal.a
es un valor de longitud dos , que contiene dos bytes, valores hexadecimales C3 y A1, mientras queua
es un valor unicode de longitud uno , que contiene un punto de código U + 00E1.Esta diferencia de longitud es una de las principales razones para utilizar valores Unicode; no puede medir fácilmente el número de caracteres de texto en una cadena de bytes; el
len()
de una cadena de bytes le dice cuántos bytes se usaron, no cuántos caracteres se codificaron.Puede ver la diferencia cuando codifica el valor Unicode en diferentes codificaciones de salida:
Tenga en cuenta que los primeros 256 puntos de código del estándar Unicode coinciden con el estándar Latin 1, por lo que el punto de código U + 00E1 se codifica en Latin 1 como un byte con valor hexadecimal E1.
Además, Python usa códigos de escape en representaciones de cadenas de bytes y unicode por igual, y los puntos de código bajo que no son ASCII imprimibles también se representan usando
\x..
valores de escape. Es por eso que una cadena Unicode con un punto de código entre 128 y 255 se parece a la codificación Latin 1. Si tiene una cadena Unicode con puntos de código más allá de U + 00FF,\u....
se usa una secuencia de escape diferente , con un valor hexadecimal de cuatro dígitos.Parece que aún no comprende completamente cuál es la diferencia entre Unicode y una codificación. Lea los siguientes artículos antes de continuar:
El mínimo absoluto que todo desarrollador de software debe conocer absoluta y positivamente sobre Unicode y conjuntos de caracteres (¡sin excusas!) Por Joel Spolsky
El CÓMO de Python Unicode
Unicode pragmático por Ned Batchelder
fuente
\xe1
en latín 1.Cuando define a como Unicode, los caracteres ay á son iguales. De lo contrario, á cuenta como dos caracteres. Pruebe len (a) y len (au). Además de eso, es posible que deba tener la codificación cuando trabaje con otros entornos. Por ejemplo, si usa md5, obtiene diferentes valores para ay ua
fuente