Previous Up Next

Capítulo ‍6 Cadenas

6.1 Una cadena es una secuencia

Una cadena es una secuencia de caracteres. Puedes acceder a los caracteres de uno en uno con el operador corchete:

>>> fruta = 'banana'
>>> letra = fruta[1]

La segunda sentencia extrae el carácter en la posición índice 1 de la variable fruta y lo asigna a la variable letra.

La expresión entre corchetes recibe el nombre de índice. El índice indica a qué carácter de la secuencia se desea acceder (de ahí su nombre).

Pero puede que no obtengas exactamente lo que esperabas:

>>> print letra
a

Para la mayoría de la gente, la primera letra de 'banana' es b, no a. Pero en Python, el índice es un seguimiento desde el comienzo de la cadena, y el seguimiento para la primera letra es cero.

>>> letra = fruta[0]
>>> print letra
b

De modo que b es la “cero-ésima” letra de 'banana', a es la primera letra, y n es la segunda.

Se puede utilizar cualquier expresión, incluyendo variables y operadores, como índice, pero el valor del índice debe ser un entero. Si no es así obtendrás:

>>> letra = fruta[1.5]
TypeError: string indices must be integers

6.2 Obtener la longitud de una cadena mediante len

len es una función interna que devuelve el número de caracteres de una cadena:

>>> fruta = 'banana'
>>> len(fruta)
6

Para obtener la última letra de una cadena, puedes sentirte tentado a intentar algo como esto:

>>> longitud = len(fruta)
>>> ultima = fruta[longitud]
IndexError: string index out of range

La razón de que se produzca un IndexError es que no hay ninguna letra en ’banana’ cuyo índice sea 6. Dado que comenzamos a contar desde cero, las seis letras son numeradas desde 0 hasta 5. Para obtener el último carácter, debes restar 1 a length:

>>> ultima = fruta[longitud-1]
>>> print ultima
a

Como alternativa, se pueden usar índices negativos, que cuentan hacia atrás desde el final de la cadena. La expresión fruta[-1] obtiene la última letra, fruta[-2] extrae la segunda desde el final, y así todas las demás.

6.3 Recorrido a través de una cadena con un bucle

Muchas operaciones implican procesar una cadena carácter por carácter. A menudo se empieza por el principio, se van seleccionando caracteres de uno en uno, se hace algo con ellos, y se continúa hasta el final. Este modelo de procesado recibe el nombre de recorrido. Una forma de escribir un recorrido es usar un bucle while:

indice = 0
while indice < len(fruta):
    letra = fruta[indice]
    print letra
    indice = indice + 1

Este bucle recorre la cadena y muestra cada letra en su propia línea. La condición del bucle es indice < len(fruta), de modo que cuando indice es igual a la longitud de la cadena, la condición es falsa, y el cuerpo del bucle no se ejecuta. El último carácter al que se accede es el que tiene el índice len(fruta)-1, que resulta ser el último carácter de la cadena.

Ejercicio ‍1 Escribe un bucle while que comience en el último carácter de la cadena y haga su recorrido hacia atrás hasta el primer carácter de la misma, mostrando cada letra en una línea separada.

Otro modo de escribir un recorrido es con un bucle for:

for car in fruta:
    print car

Cada vez que se recorre el bucle, el carácter siguiente de la cadena es asignado a la variable car. El bucle continúa hasta que no quedan caracteres.

6.4 Rebanado de cadenas (slicing)

Un segmento de una cadena recibe el nombre de rebanada (slice). Seleccionar una rebanada es similar a seleccionar caracteres:

>>> s = 'Monty Python'
>>> print s[0:5]
Monty
>>> print s[6:12]
Python

El operador [n:m] devuelve la parte de la cadena desde el “n-ésimo” carácter hasta el “m-ésimo”, incluyendo el primero pero excluyendo el último.

Si se omite el primer índice (el que va antes de los dos-puntos), la rebanada comenzará al principio de la cadena. Si el que se omite es el segundo, la rebanada abarcará hasta el final de la cadena:

>>> fruta = 'banana'
>>> fruta[:3]
'ban'
>>> fruta[3:]
'ana'

Si el primer índice es mayor o igual que el segundo, el resultado será una cadena vacía, representada por dos comillas:

>>> fruta = 'banana'
>>> fruta[3:3]
"

Una cadena vacía no contiene caracteres y tiene una longitud 0, pero por lo demás es exactamente igual que cualquier otra cadena.

Ejercicio ‍2 Dado que fruta es una cadena, ¿qué significa fruta[:]?

6.5 Las cadenas son inmutables

Resulta tentador el utilizar el operador [] en la parte izquierda de una asignación, con la intención de cambiar un carácter en una cadena. Por ejemplo:

>>> saludo = '¡Hola, mundo!'
>>> saludo[0] = 'J'
TypeError: object does not support item assignment

Error de tipado: El objeto no soporta la asignación del elemento. El “objecto” (object) en este caso es la cadena y el “elemento” (item) es el carácter que intentabas asignar. Por ahora, consideraremos que un objeto es lo mismo que un valor, aunque mejoraremos esa definición más adelante. Un elemento es uno de los valores en una secuencia.

La razón del error es que las cadenas son inmutables, lo cual significa que no se puede cambiar una cadena existente. Lo mejor que se puede hacer en estos casos es crear una cadena nueva que sea una variación de la original:

>>> saludo = '¡Hola, mundo!'
>>> nuevo_saludo = 'J' + saludo[1:]
>>> print nuevo_saludo
JHola, mundo!

Este ejemplo concatena una primera letra nueva en una rebanada (slice) de saludo. Esto conserva intacta la cadena original.

6.6 Bucles y contadores

El siguiente programa cuenta el número de veces que aparece la letra a en una cadena:

palabra = 'banana'
contador = 0
for letra in palabra:
    if letra == 'a':
        contador = contador + 1
print contador

Este programa demuestra otro diseño del cálculo llamado contador. La variable contador es inicializada a 0 y después es incrementada cada vez que se encuentra una a. Cuando se sale del bucle, contador contiene el resultado—el número total de a’es

Ejercicio ‍3

Encapsula el código anterior en una función llamada contador, y generalízala, de modo que acepte la cadena y la letra como argumentos.

6.7 El operador in

La palabra in es un operador booleano que toma dos cadenas y devuelve True (verdadero) si la primera aparece como subcadena dentro de la segunda:

>>> 'a' in 'banana'
True
>>> 'seed' in 'banana'
False

6.8 Comparación de cadenas

El operador de comparación funciona con cadenas. Para comprobar si dos cadenas son iguales:

if palabra == 'banana':
    print  'De acuerdo, bananas.'

Otros operadores de comparación resultan útiles para colocar palabras en orden alfabético:

if palabra < 'banana':
    print 'Tu palabra,' + palabra + ', va antes que banana.'
elif palabra > 'banana':
    print 'Tu palabra,' + palabra + ', va después que banana.'
else:
    print 'De acuerdo, bananas.'

Python no maneja las mayúsculas y minúsculas del mismo modo en que lo hacen las personas. Todas las letras mayúsculas van antes que las minúsculas, de modo que:

Tu palabra, Piña, va antes que banana.

Un método habitual para evitar este problema es convertir las cadenas a un formato estándar, por ejemplo todas a minúsculas, antes de realizar la comparación. Tenlo en cuenta en el caso de que tengas que defenderte de un hombre armado con una Piña.

6.9 Métodos de cadenas

Las cadenas son un ejemplo de objetos en Python. Un objeto contiene tanto datos (la propia cadena en si misma) como métodos, que en realidad son funciones que están construidas dentro de los propios objetos y que están disponibles para cualquier instancia del objeto.

Python dispone de una función llamada dir que lista los métodos disponibles para un objeto. La función type muestra el tipo de cualquier objeto y la función dir muestra los métodos disponibles.

>>> cosa = '¡Hola, mundo!'
>>> type(cosa)
<type 'str'>
>>> dir(cosa)
['capitalize', 'center', 'count', 'decode', 'encode', 
'endswith', 'expandtabs', 'find', 'format', 'index', 
'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 
'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 
'partition', 'replace', 'rfind', 'rindex', 'rjust', 
'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 
'startswith', 'strip', 'swapcase', 'title', 'translate', 
'upper', 'zfill']
>>> help(str.capitalize)
Help on method_descriptor:

capitalize(...)
    S.capitalize() -> string
    
    Return a copy of the string S with only its first character
    capitalized.
>>>

A pesar de que la función dir lista los métodos, y de que puedes usar help para obtener un poco de información sobre cada método, una fuente de documentación mejor para los métodos de las cadenas se puede encontrar en https://docs.python.org/2/library/stdtypes.html#string-methods.

Llamar a un método es similar a llamar a una función—toma argumentos y devuelve un valor—pero la sintaxis es diferente. Un método se usa uniendo el nombre del método al de la variable, utilizando el punto como delimitador.

Por ejemplo, el método upper toma una cadena y devuelve otra nueva con todas las letras en mayúsculas:

En vez de usar la sintaxis de función upper(palabra), se usa la sintaxis de método palabra.upper().

>>> palabra = 'banana'
>>> nueva_palabra = palabra.upper()
>>> print nueva_palabra
BANANA

Esta forma de notación con punto especifica el nombre del método, upper, y el nombre de la cadena a la cual se debe aplicar ese método, palabra. Los paréntesis vacíos indican que el método no toma argumentos.

Una llamada a un método se denomina invocación; en este caso, diríamos que estamos invocando el método upper de palabra.

Por ejemplo, he aquí un método de cadena llamado find, que busca la posición de una cadena dentro de otra:

>>> palabra = 'banana'
>>> indice = palabra.find('a')
>>> print indice
1

En este ejemplo, se invoca el método find de palabra y se le pasa como parámetro la letra que estamos buscando.

El método find puede encontrar tanto subcadenas como caracteres:

>>> palabra.find('na')
2

Puede tomar un segundo argumento que indica en qué posición debe comenzar la búsqueda:

>>> palabra.find('na', 3)
4

Una tarea habitual es eliminar espacios en blanco (espacios, tabulaciones, saltos de línea) del principio y del final de una cadena usando el método strip:

>>> linea = '  Y allá vamos  '
>>> linea.strip()
'Y allá vamos'

Algunos métodos como startswith devuelven valores booleanos.

>>> linea = 'Que tengas un buen día'
>>> linea.startswith('Que')
True
>>> linea.startswith('q')
False

Te habrás fijado que startswith necesita que las mayúsculas también coincidan, de modo que a veces tomaremos una línea y la convertiremos por completo a minúsculas antes de hacer ninguna comprobación, usando para ello el método lower.

>>> linea = 'Que tengas un buen día'
>>> linea.startswith('q')
False
>>> linea.lower()
'que tengas un buen día'
>>> linea.lower().startswith('q')
True

En el último ejemplo, se llama al método lower y después se usa startswith para comprobar si la cadena resultante en minúsculas comienza por la letra “q”. Mientras tengamos cuidado con el orden en que las aplicamos, podemos hacer múltiples llamadas a métodos en una única expresión..

Ejercicio ‍4

Existe un método de cadena llamado count, que es similar a la función que vimos en el ejercicio anterior. Lee la documentación de este método en https://docs.python.org/2/library/stdtypes.html#string-methods y escribe una invocación que cuente el número de veces que aparece la letra “a” en 'banana'.

6.10 Análisis de cadenas

A menudo tendremos que mirar en el interior una cadena para localizar una subcadena. Por ejemplo, si se nos presentan una serie de líneas formateadas de este modo:


From stephen.marquard@ uct.ac.za Sat Jan  5 09:14:16 2008

y queremos extraer sólo la segunda mitad de la dirección (es decir, uct.ac.za) de cada línea, podemos hacerlo usando el método find y rebanando (slicing) la cadena.

En primer lugar, buscaremos la posición del símbolo arroba en la cadena. Después, buscaremos la posición del primer espacio después de la arroba. Y a continuación rebanaremos la cadena para extraer la porción de la misma que estamos buscando.

>>> datos = 'From [email protected] Sat Jan  5 09:14:16 2008'
>>> pos_arroba = datos.find('@')
>>> print pos_arroba
21
>>> pos_esp = datos.find(' ',pos_arroba)
>>> print pos_esp
31
>>> host = data[pos_arroba+1:pos_esp]
>>> print host
uct.ac.za
>>> 

Usamos la versión del método find que nos permite especificar una posición en la cadena desde la cual queremos que find empiece a buscar. Cuando rebanamos, extraemos los caracteres desde “uno más allá de la arroba hasta (pero no incluyendo) el carácter espacio”.

La documentación para el método find está disponible en https://docs.python.org/2/library/stdtypes.html#string-methods.

6.11 Operador de formato

El operador de formato %, nos permite construir cadenas, reemplazando parte de esas cadenas con los datos almacenados en variables. Cuando se aplica a enteros, % es el operador módulo. Pero cuando el primer operando es una cadena, % es el operador formato.

El primer operando es la cadena a formatear, que contiene una o más secuencias de formato, que especifican cómo será formateado el segundo operador. El resultado es una cadena.

Por ejemplo, la secuencia de formato '%d' quiere decir que el segundo operador debe ser formateado como un entero (d indica “decimal”):

>>> camellos = 42
>>> '%d' % camellos
'42'

El resultado es la cadena '42', que no hay que confundir con el valor entero 42.

Una secuencia de formato puede aparecer en cualquier sitio de la cadena, de modo que puedes insertar un valor en una frase:

>>> camellos = 42
>>> 'He divisado %d camellos.' % camellos
'He divisado 42 camellos.'

Si hay más de una secuencia de formato en la cadena, el segundo argumento debe ser una tupla1. Cada secuencia de formato se corresponde con un elemento de la tupla, en orden.

El ejemplo siguiente usa '%d' para formatear un entero, '%g' para formatear un número en punto flotante (no preguntes por qué), y '%s' para formatear una cadena:

>>> 'En %d años he divisado %g %s.' % (3, 0.1, 'camellos')
'En 3 años he divisado 0.1 camellos.'

El número de elementos en la tupla debe coincidir con el número de secuencias de formato en la cadena. El tipo de los elementos debe coincidir también con las secuencias de formato:

>>> '%d %d %d' % (1, 2)
TypeError: not enough arguments for format string
>>> '%d' % 'dólares'
TypeError: illegal argument type for built-in operation

En el primer ejemplo, no hay suficientes elementos; en el segundo, el elemento es de tipo incorrecto.

El operador de formato es potente, pero puede resultar difícil de utilizar. Puedes leer más sobre él en https://docs.python.org/2/library/stdtypes.html#string-formatting.

6.12 Depuración

Una capacidad que deberás desarrollar cuando programes es la de estar preguntándote siempre: “¿Qué podría salir mal aquí?”, o también, “¿Qué locura puede hacer el usuario para destrozar nuestro (aparentemente) perfecto programa?”

Por ejemplo, mira el programa que usamos para demostrar el bucle while en el capítulo dedicado a la iteración:

while True:
    linea = raw_input('> ')
    if linea[0] == '#' :
        continue
    if linea == 'fin':
        break
    print linea

print '¡Terminado!'

Mira lo que sucede cuando el usuario introduce una línea vacía como entrada:

> hola a todos
hola a todos
> # no imprimas esto
> ¡imprime esto!
¡imprime esto!
> 
Traceback (most recent call last):
  File "copytildone.py", line 3, in <module>
    if linea[0] == '#' :

El código funciona hasta que se le presenta una línea vacía. Entonces, como no hay carácter cero-ésimo, obtenemos un traceback. Existen dos soluciones a esto para convertir la línea tres en “segura”, incluso cuando la entrada sea una cadena vacía.

Una posibilidad es simplemente usar el método startswith, que devuelve False (falso) si la cadena está vacía.

    if linea.startswith('#') :

Otro modo es asegurar la sentencia if usando el patrón guardián, y asegurarnos de que la segunda expresión lógica sea evaluada sólo cuando hay al menos un carácter en la cadena:

    if len(linea) > 0 and linea[0] == '#' :

6.13 Glosario

búsqueda:
Un diseño de recorrido que se detiene cuando encuentra lo que está buscando.
cadena vacía:
Una cadena sin caracteres y de longitud 0, representada por dos comillas.
contador:
Una variable utilizada para contar algo, normalmente inicializada a cero y luego incrementada.
cadena a formatear:
Una cadena, usada con el operador de formato, que contiene secuencias de formato.
elemento:
Uno de los valores en una secuencia.
flag (bandera):
Una variable booleana que se usa para indicar si una condición es verdadera.
índice:
Un valor entero usado para seleccionar un elemento de una secuencia, como puede ser un carácter en una cadena.
inmutable:
La propiedad de una secuencia cuyos elementos no pueden ser asignados.
invocación:
Una sentencia que llama a un método.
método:
Una función que está asociada con un objeto y es llamada usando la notación punto.
objecto:
Algo a lo que puede referirse una variable. Por ahora, puedes usar “objeto” y “valor” indistintamente.
operador de formato:
Un operador, %, que toma una cadena a formatear y una tupla y genera una cadena que incluye los elementos de la tupla formateados como se especifica en la cadena de formato.
rebanada (slice):
Una parte de una cadena especificada por un rango de índices.
recorrido:
Iterar a través de los elementos de una secuencia, realizando un operación similar en cada uno de ellos.
secuencia:
Un conjunto ordenado; es decir, un conjunto de valores donde cada valor está identificado por un índice entero.
secuencia de formato:
Una secuencia de caracteres en una cadena de formato, como %d, que especifica cómo debe ser formateado un valor.

6.14 Ejercicios

Ejercicio ‍5 Toma el código en Python siguiente, que almacena una cadena:‘

cad = ’X-DSPAM-Confidence:  0.8475

Usa find y rebanado de cadenas (slicing) para extraer la porción de la cadena después del carácter punto, y luego usa la función float para convertir la cadena extraída en un número en punto flotante.

Ejercicio ‍6

Lee la documentación de los métodos de cadena que está en https://docs.python.org/2/library/stdtypes.html#string-methods. Puede que quieras experimentar con algunos de ellos para asegurarte de que comprendes cómo funcionan. strip y replace resultan particularmente útiles.

La documentación utiliza una sintaxis que puede resultar confusa. Por ejemplo, en find(sub[, start[, end]]), los corchetes indican argumentos opcionales. De modo que sub es necesario, pero start es opcional, y si incluyes start, entonces end es opcional.


1
Una tupla es una secuencia de valores separados por comas dentro de unos paréntesis. Veremos las tuplas en el capítulo 10

Previous Up Next