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
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.
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.
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.
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.
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.
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
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.
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
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.
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..
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'
.
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.
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.
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] == '#' :
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.
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.