# Strings (Python)

Una explicación de cómo trabajar con cadenas en Python y GTK+.
Sebastian Pölsterl
sebp@k-d-w.org 2011
Marta Maria Casetti
mmcasetti@gmail.com 2012

# Cadenas

# Definiciones

Conceptualmente, una cadena es una lista de caracteres como «A», «B», «C», o «È». Los caracteres son representaciones abstractas y su significado depende del lenguaje y el contexto en el que se usan. El estándar Unicode describe cómo sus significados se representan por puntos de código. Por ejemplo, los caracteres anteriores se representan con los puntos de código U+0041, U+0042, U+0043, y U+00C9, respectivamente. Básicamente, los puntos de código son números entre 0 y 0x10FFFF

La representación de una cadena como una lista de puntos de código es abstracta. Para convertir esta representación abstracta en una secuencia de bytes, la cadena de Unicode debe codificarse. La forma más simple de codificación es ASCII y se ejecuta de la siguiente manera:

Si el punto de código es estrictamente menos de 128, cada byte es igual al valor del punto de código.

Si el punto de código es 128 o mayor, la cadena de Unicode no puede representarse en esta codificación. (Python eleva una excepción UnicodeEncodeError en este caso).

A pesar de que la codificación ASCII es simple de aplicar, sólo puede codificar 128 caracteres diferentes, lo que no es suficiente. Una de las codificaciones usadas más comúnmente que resuelve este problema es UTF-8 (puede manejar cualquier punto de código Unicode). UTF significa «Formato de Transformación de Unicode», y el «8» significa que se usan números de 8 bits en esta codificación.

# Cadenas en Python 2

Python 2 viene con dos tipos de objetos diferentes que pueden usarse para representar cadenas, `str` y `unicode`. Las instancias de `unicode` se usan para expresar cadenas de Unicode, mientras que las instancias del tipo `str` son representaciones de bytes (la cadena codificada). A nivel funcional, Python representa las cadenas de Unicode como enteros de 16 ó 32 bits, dependiendo de cómo se compiló su intérprete.

>>> unicode_string = u"Fu\u00dfb\u00e4lle" >>> print unicode_string Fußbälle

Las cadenas de Unicode pueden convertirse a cadenas de 8 bits con `unicode.encode()`. Las cadenas de 8 bits de Python tienen un método `str.decode()` que interpreta la cadena usando la codificación dada (es decir, es la inversa de `unicode.encode()`):

>>> type(unicode_string) <type 'unicode'> >>> unicode_string.encode("utf-8") 'Fu\xc3\x9fb\xc3\xa4lle' >>> utf8_string = unicode_string.encode("utf-8") >>> type(utf8_string) <type 'str'> >>> unicode_string == utf8_string.decode("utf-8") True

Desafortunadamente, Python 2.x le permite mezclar `unicode` y `str` si la cadena de 8 bits contuviera sólo bytes de 7 bits (ASCII), pero obtendría UnicodeDecodeError si contuviera valores no ASCII.

# Cadenas en Python 3

Desde Python 3.0, todas las cadenas se almacenan como Unicode en una instancia del tipo `str`. Las cadenas codificadas, por otro lado, se representan como datos binarios en la forma de instancias del tipo de bytes. Conceptualmente, `str` se refiere a texto, mientras que bytes se refieren a datos. Use `encode()` para ir de `str` a `bytes`, y `decode()` para ir de `bytes` a `str`.

Además, ya no es posible mezclar cadenas de Unicode con cadenas codificadas, porque se producirá un `TypeError`:

>>> text = "Fu\u00dfb\u00e4lle" >>> data = b" sind rund" >>> text + data Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't convert 'bytes' object to str implicitly >>> text + data.decode("utf-8") 'Fußbälle sind rund' >>> text.encode("utf-8") + data b'Fu\xc3\x9fb\xc3\xa4lle sind rund'

# Unicode en GTK+

GTK+ usa cadenas codificadas con UTF-8 para todo el texto. Esto significa que si llama a un método que devuelve una cadena, siempre obtendrá una instancia del tipo `str`. Lo mismo se aplica a métodos que esperan una o más cadenas como parámetro, deben estar codificadas con UTF-8. Sin embargo, por comodidad, PyGObject convertirá automáticamente cualquier instancia de Unicode a «str» si se proporciona como argumento:

>>> from gi.repository import Gtk >>> label = Gtk.Label() >>> unicode_string = u"Fu\u00dfb\u00e4lle" >>> label.set_text(unicode_string) >>> txt = label.get_text() >>> type(txt) <type 'str'>

Además:

>>> txt == unicode_string

devolvería `False`, con la advertencia `__main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal` (`Gtk.Label.get_text()` devolverá siempre una instancia de `str`; por lo tanto, `txt` y `unicode_string` no son iguales).

Esto es especialmente importante si quiere internacionalizar su programa usando `gettext`. Tiene que asegurarse de que `gettext` devuelva cadenas de 8 bits codificadas con UTF-8 para todos los idiomas.

En general se recomienda no usar ningún objeto de `unicode` en aplicaciones de GTK+, y sólo usar objetos `str` codificados con UTF-8 dado que GTK+ no integra completamente objetos `unicode`.

Con Python 3.x las cosas son mucho más consistentes, porque PyGObject automáticamente codifica/decodifica hacia/desde UTF-8 si le pasa una cadena a un método o un método devuelve una cadena. Las cadenas, o el texto, siempre se representarán sólo como instancias de `str`:

# Referencias

How To Deal With Strings - The Python GTK+ 3 Tutorial