Chapter 7
Cadenas
7.1 Un tipo de datos compuesto
Hasta el momento hemos visto tres tipos: int, float, y string. Las cadenas son cuantitativamente diferentes de los otros dos
porque est�n hechas de piezas menores: caracteres.
Los tipos que comprenden piezas menores se llaman tipos de datos
compuestos. Dependiendo de qu� estemos haciendo, podemos querer tratar
un tipo compuesto como una �nica cosa o acceder a sus partes. Esta
ambig�edad es �til.
El operador corchete selecciona un car�cter suelto de una cadena.
>>> fruta = "banana"
>>> letra = fruta[1]
>>> print letra
La expresi�n fruta[1] selecciona el car�cter n�mero 1 de fruta. La variable letra apunta al resultado. Cuando mostramos
letra, nos encontramos con una sorpresa:
a
La primera letra de "banana" no es a. A no ser que usted sea un
programador. Por perversas razones, los cient�ficos de la computaci�n siempre
empiezan a contar desde cero. La 0-sima letra ("cer�sima") de "banana"es b. La 1-�sima ("un�sima") es a, y la 2-�sima ("dos�sima") letra
es n.
Si quiera la cer�sima letra de una cadena, simplemente pone 0, o cualquier
expresi�n de valor 0, entre los corchetes:
>>> letra = fruta[0]
>>> print letra
b
A la expresi�n entre corchetes se le llama �ndice. Un �ndice identifica
a un miembro de un conjunto ordenado, en este caso el conjunto de caracteres
de la cadena. El �ndice indica cu�l quiere usted, de ah� el nombre. Puede
ser cualquier expresi�n entera.
7.2 Longitud
La funci�n len devuelve el n�mero de caracteres de una cadena:
>>> fruta = "banana"
>>> len(fruta)
6
Para obtener la �ltima letra de una cadena puede sentirse tentado a probar
algo como esto:
longitud = len(fruta)
ultima = fruta[longitud]
Eso no funcionar�. Provoca un error en tiempo de ejecuci�n IndexError:
string index out of range. La raz�n es que no hay una sexta letra en
"banana". Como empezamos a contar por cero, las seis letras est�n
numeradas del 0 al 5. Para obtener el �ltimo car�cter tenemos que restar
1 de longitud:
longitud = len(fruta)
ultima = fruta[longitud-1]
De forma alternativa, podemos usar �ndices negativos, que cuentan hacia
atr�s desde el final de la cadena. La expresi�n fruta[-1] nos da
la �ltima letra. fruta[-2] nos da la pen�ltima, y as�.
7.3 Recorrido y el bucle \tt{for
\label{for}
\index{recorrido}
\index{bucle!recorrido}
\index{bucle for}
\index{bucle!for}
Muchos c�lculos incluyen el proceso de una cadena car�cter a car�cter.
A menudo empiezan por el principio, seleccionan cada car�cter por turno,
hacen algo con �l y siguen hasta el final. Este patr�n de proceso se llama
{\bf recorrido}. Una forma de codificar un recorrido es una sentencia
\verb|while|:
\adjustpage{2}
\beforeverb
\begin{verbatim}
indice = 0
while indice < len(fruta):
letra = fruta[indice]
print letra
indice = indice + 1
\end{verbatim}
\afterverb
%
Este bucle recorre la cadena y muestra cada letra en una l�nea distinta.
La condici�n del bucle es \verb|indice < len(fruta)|, de modo que cuando
\verb|indice| es igual a la longitud de la cadena, la condici�n es falsa
y no se ejecuta el cuerpo del bucle. El �ltimo car�cter al que se accede
es el que tiene el �ndice \verb|len(fruta)-1|, que es el �ltimo car�cter
de la cadena.
\begin{quote}
{\em Como ejercicio, escriba una funci�n que tome una cadena como argumento
y entregue las letras en orden inverso, una por l�nea.}
\end{quote}
Es tan habitual usar un �ndice para recorrer un conjunto de valores que
Python facilita una sintaxis alternativa m�s simple: el bucle \verb|for|:
\beforeverb
\begin{verbatim}
for car in fruta:
print car
\end{verbatim}
\afterverb
%
Cada vez que recorremos el bucle, se asigna a la variable \verb|car| el
siguiente car�cter de la cadena. El bucle contin�a hasta que no quedan
caracteres.
\index{concatenaci�n}
\index{abeced'arico}
\index{McCloskey, Robert}
\index{{\em Make Way for Ducklings}}
El ejemplo siguiente muestra c�mo usar la concatenaci�n junto a un
bucle {\tt for} para generar una serie abeced�rica. ``Abeced�rica'' es
la serie o lista en la que cada uno de los elementos aparece en orden
alfab�tico. Por ejemplo, en el libro de Robert McCloskey {\em Make Way
for Ducklings (Dejad paso a los patitos)}, los nombres de los patitos
son Jack, Kack, Lack, Mack, Nack, Ouack, Pack, y Quack. Este bucle
saca esos nombres en orden:
\beforeverb
\begin{verbatim}
prefijos = "JKLMNOPQ"
sufijo = "ack"
for letra in prefijos:
print letra + sufijo
\end{verbatim}
\afterverb
%
La salida del programa es:
\beforeverb
\begin{verbatim}
Jack
Kack
Lack
Mack
Nack
Oack
Pack
Qack
\end{verbatim}
\afterverb
%
Por supuesto, esto no es del todo correcto, porque ``Ouack'' y ``Quack'' no
est�n correctamente escritos.
\begin{quote}
{\em Como ejercicio, modifique el programa para corregir este error.}
\end{quote}
\section{Porciones de cadenas}
\label{slice}
\index{porci�n}
\index{cadena!porci�n}
Llamamos {\bf porci�n} a un segmento de una cadena. La selecci�n de una porci�n
es similar a la selecci�n de un car�cter:
\beforeverb
\begin{verbatim}
>>> s = "Pedro, Pablo, y Mar�a"
>>> print s[0:5]
Pedro
>>> print s[7:12]
Pablo
>>> print s[15:20]
Mar�a
\end{verbatim}
\afterverb
%
El operador \verb|[n:m]| devuelve la parte de la cadena desde el en�simo
car�cter hasta el ``em�simo'', incluyendo el primero pero excluyendo el �ltimo.
Este comportamiento contradice a nuestra intuici�n; tiene m�s sentido si imagina los
�ndices se�alando {\em entre} los caracteres, como en el siguiente diagrama:
\beforefig
\centerline{\psfig{figure=../illustrations/banana.eps}}
\afterfig
Si omite el primer �ndice (antes de los dos puntos), la porci�n comienza al
principio de la cadena. Si omite el segundo �ndice, la porci�n llega al final
de la cadena. As�:
\beforeverb
\begin{verbatim}
>>> fruta = "banana"
>>> fruta[:3]
'ban'
>>> fruta[3:]
'ana'
\end{verbatim}
\afterverb
%
�Qu� cree usted que significa \verb|s[:]|?
\section{Comparaci�n de cadenas}
\index{comparaci�n de cadenas}
\index{comparaci�n!cadenas}
Los operadores de comparaci�n trabajan sobre cadenas. Para ver si dos cadenas
son iguales:
\beforeverb
\begin{verbatim}
if palabra == "banana":
print "S�, no tenemos bananas!"
\end{verbatim}
\afterverb
%
\adjustpage{-2}
Otras operaciones de comparaci�n son �tiles para poner palabras en orden
alfab�tico:
\beforeverb
\begin{verbatim}
if palabra < "banana":
print "Tu palabra," + palabra + ", va antes de banana."
elif palabra > "banana":
print "Tu palabra," + palabra + ", va despu�s de banana."
else:
print "S�, no tenemos bananas!"
\end{verbatim}
\afterverb
%
Sin embargo, deber�a usted ser consciente de que Python no maneja las
may�sculas y min�sculas como lo hace la gente. Todas las may�suculas
van antes de la min�sculas. Como resultado de ello:
\beforeverb
\begin{verbatim}
Tu palabra, Zapato, va antes de banana.
\end{verbatim}
\afterverb
%
Una forma com�n de abordar este problema es convertir las cadenas a un
formato est�ndar, como pueden ser las min�sculas, antes de realizar la
comparaci�n. Un problema mayor es hacer que el programa se d� cuenta de
que los zapatos no son frutas.
\section{Las cadenas son inmutables}
\index{mutable}
\index{cadena inmutable}
\index{cadena!inmutable}
Es tentador usar el operador \verb|[]| en el lado izquierdo de una
asignaci�n, con la intenci�n de cambiar un car�cter en una cadena.
Por ejemplo:
\beforeverb
\begin{verbatim}
saludo = "Hola, mundo"
saludo[0] = 'M' # ERROR!
print saludo
\end{verbatim}
\afterverb
%
En lugar de presentar la salida \verb|Mola, mundo|, este c�digo presenta
el siguiente error en tiempo de ejecuci�n {\tt TypeError: object doesn't
support item assignment}.
\index{error en tiempo de ejecuci�n}
Las cadenas son {\bf inmutables}, lo que significa que no puede
cambiar una cadena existente. Lo m�s que puede hacer es crear una
nueva cadena que sea una variaci�n de la original:
\beforeverb
\begin{verbatim}
saludo = "Hola, mundo"
nuevoSaludo = 'M' + saludo[1:]
print nuevoSaludo
\end{verbatim}
\afterverb
%
Aqu� la soluci�n es concatenar una nueva primera letra a una porci�n de
\verb|saludo|. Esta operaci�n no tiene efectos sobre la cadena original.
\index{concatenaci�n}
\adjustpage{-2}
\section{Una funci�n ``encuentra''}
\label{encuentra}
\index{recorrido}
\index{recorrido eureka}
\index{patr�n}
\index{patr�n computacional}
�Qu� hace la siguiente funci�n?
\beforeverb
\begin{verbatim}
def encuentra(cad, c):
indice = 0
while indice < len(cad):
if cad[indice] == c:
return indice
indice = indice + 1
return -1
\end{verbatim}
\afterverb
%
En cierto sentido, \verb|encuentra| es lo contrario del operador
\verb|[]|. En lugar de tomar un �ndice y extraer el car�cter
correspondiente, toma un car�cter y encuentra el �ndice donde
aparece el car�cter. Si el car�cter no se encuentra, la funci�n
devuelve {\tt -1}.
Este es el primer ejemplo que hemos visto de una sentencia \verb|return|
dentro de un bucle. Si \verb|cad[indice] == c|, la funci�n vuelve
inmediatamente, escapando del bucle prematuramente.
Si el car�cter no aparece en la cadena, el programa sale del bucle
normalmente y devuelve \verb|-1|.
Este patr�n de computaci�n se llama a veces un recorrido ``eureka''
porque en cuanto encontramos lo que buscamos, podemos gritar ``�Eureka!''
y dejar de buscar.
\begin{quote}
{\em A modo de ejercicio, modifique la funci�n \verb|encuentra| para que
acepte un tercer par�metro, el �ndice de la cadena donde deber�a empezar
a buscar.}
\end{quote}
\section{Bucles y conteo}
\label{contador}
\index{contador}
\index{patr�n}
El programa que sigue cuenta el n�mero de veces que la letra \verb|a|
aparece en una cadena:
\beforeverb
\begin{verbatim}
fruta = "banana"
cuenta = 0
for car in fruta:
if car == 'a':
cuenta = cuenta + 1
print cuenta
\end{verbatim}
\afterverb
%
Este programa muestra otro patr�n de computaci�n llamado {\bf contador}.
La variable \verb|cuenta| se incializa a 0 y luego se incrementa cada
vez que se encuentra una \verb|a|. ({\bf Incrementar} es aumentar en
uno; es lo contario de {\bf decrementar}, y sin relaci�n alguna con
``excremento'', que es un nombre.) Al salir del bucle, \verb|cuenta|
contiene el resultado -- el n�mero total de \verb|a|es.
\begin{quote}
{\em Como ejercicio, encapsule este c�digo en una funci�n llamada {\tt
cuentaLetras}, y general�cela de forma que acepte la cadena y la letra
como par�metros.}
\end{quote}
\begin{quote}
{\em Como un segundo ejercicio, reescriba esta funci�n para que en lugar
de recorrer la cadena, use la versi�n de tres par�metros de {\tt encuentra
del anterior}.}
\end{quote}
\section{El m�dulo ``string''}
\index{m�dulo}
\index{m�dulo string}
El m�dulo \verb|string| contiene funciones �tiles para manipular cadenas.
Como es habitual, tenemos que importar el m�dulo antes de poder usarlo:
\beforeverb
\begin{verbatim}
>>> import string
\end{verbatim}
\afterverb
%
El m�dulo \verb|string| incluye una funci�n llamada \verb|find| que hace lo
mismo que la funci�n \verb|encuentra| que escribimos. Para llamarla debemos
especificar el nombre del m�dulo y el nombre de la funci�n por medio de la
notaci�n de punto.
\beforeverb
\begin{verbatim}
>>> fruta = "banana"
>>> indice = string.find(fruta, "a")
>>> print indice
1
\end{verbatim}
\afterverb
%
Este ejemplo demuestra uno de los beneficios de los m�dulos: ayudan a evitar
las colisiones entre los nombres de las funciones predefinidas y las definidas
por el usuario. Al usar la notaci�n de punto podr�amos especificar qu� versi�n
de \verb|find| queremos en caso de haberle daddo un nombre en ingl�s a nuestra
funci�n.
En realidad, \verb|string.find| es m�s general que nuestra versi�n. Para
empezar, puede encontrar subcadenas, no s�lo caracteres:
\beforeverb
\begin{verbatim}
>>> string.find("banana", "na")
2
\end{verbatim}
\afterverb
%
Adem�s, acepta un argumento adicional que especifica el �ndice en el que
deber�a comenzar:
\beforeverb
\begin{verbatim}
>>> string.find("banana", "na", 3)
4
\end{verbatim}
\afterverb
%
O puede tomar dos argumentos adicionales que especifican un intervalo de
�ndices:
\beforeverb
\begin{verbatim}
>>> string.find("sus", "s", 1, 2)
-1
\end{verbatim}
\afterverb
%
En este ejemplo, la b�squeda falla porque la letra {\em s} no aparece en
el intervalo de �ndices desde \verb|1| hasta \verb|2| (sin incluir {\tt 2}).
\section{Clasificaci�n de caracteres}
\label{in}
\index{clasificaci�n de caracteres}
\index{clasificaci�n!car�cter}
\index{uppercase}
\index{lowercase}
\index{whitespace}
A menudo viene bien examinar un car�cter y comprobar si es una letra
may�scula o min�scula, o si es un car�cter o un d�gito. El m�dulo
\verb|string| proporciona varias constantes que son �tiles para estos
menesteres.
La cadena \verb|string.lowercase| contiene todas las letras que el sistema
considera como min�sculas. De forma similar, \verb|string.uppercase|
contiene todas las may�sculas. Pruebe lo que sigue y vea qu� obtiene:
\beforeverb
\begin{verbatim}
>>> print string.lowercase
>>> print string.uppercase
>>> print string.digits
\end{verbatim}
\afterverb
%
Podemos usar estas constantes y \verb|find| para clasificar caracteres. Por
ejemplo, si \verb|find(lowercase, c)| devuelve un valor que no sea {\tt -1},
entonces \verb|c| es una min�scula:
\beforeverb
\begin{verbatim}
def esMinuscula(c):
return find(string.lowercase, c) != -1
\end{verbatim}
\afterverb
%
Alternativamente, podemos aprovecharnos del operador \verb|in|, que
determina si un car�cter aparece en una cadena:
\beforeverb
\begin{verbatim}
def esMinuscula(c):
return c in string.lowercase
\end{verbatim}
\afterverb
%
Como una alternativa m�s, podemos usar el operador de comparaci�n,
aunque esta soluci�n s�lo sea pr�ctica para el alfabeto ingl�s:
\beforeverb
\begin{verbatim}
def esMinuscula(c):
return 'a' <= c <= 'z'
\end{verbatim}
\afterverb
%
Si \verb|c| est� entre {\em a} y {\em z}, tiene que ser una min�scula.
\begin{quote}
{\em Como ejercicio, explique qu� versi�n de \verb|esMinuscula| cree que
es m�s r�pida. �Puede pensar en otras razones aparte de la velocidad para
preferir una sobre la otra?}
\end{quote}
Otra constante definida en el m�dulo \verb|string| puede sorprenderle cuando
la imprima:
\beforeverb
\begin{verbatim}
>>> print string.whitespace
\end{verbatim}
\afterverb
%
Los caracteres de {\bf whitespace} mueven el cursor sin imprimir nada. Crean
los espacios en blanco entre los caracteres visibles (al menos sobre papel
blanco). La constante \verb|string.whitespace| contiene todos los caracteres
de espacio en blanco, inclu�dos espacio, tabulador (\verb+\t+), y salto de
l�nea (\verb+\n+).
\index{m�dulo string}
\index{m�dulo!string}
Hay otras funciones �tiles en el m�dulo \verb|string|, pero este libro
no pretende ser un manual de referencia. Por otra parte, la {\em Referencia
de la Biblioteca de Python} s� lo es. Junto con un mont�n m�s de documentaci�n,
est� disponible en el sitio web de Python, {\tt www.python.org}.
\index{{\em Referencia de la Biblioteca de Python}}
\section{Glosario}
\begin{description}
\item[tipo de datos compuesto:] Un tipo de datos en el que los valores
est�n hechos de componentes o elementos que son a su vez valores.
\item[recorrer:] Realizar de forma iterativa una operaci�n similar sobre
cada uno de los elementos de un conjunto.
\item[�ndice:] Una variable o valor usado para seleccionar un miembro de
un conjunto ordenado, como puede ser un car�cter de una cadena.
\item[porci�n:] Una parte de una cadena especificada por un intervalo de
�ndices.
\item[mutable:] Un tipo de datos compuesto a cuyos elementos se les puede
asignar nuevos valores.
\item[contador:] Una variable usada para contar algo, normalmente inicializado
a cero e incrementado posteriormente.
\item[incrementar:] Aumentar el valor de una variable en una unidad.
\item[decrementar:] Disminuir el valor de una variable en una unidad.
\item[espacio en blanco:] Cualquiera de los caracteres que mueven el cursor
sin imprimir caracteres visibles. La constante \verb|string.whitespace|
contiene todos los caracterse de espacio en blanco.
\index{tipo compuesto de datos}
\index{recorrer}
\index{�ndice}
\index{porci�n}
\index{mutable}
\index{contador}
\index{incrementar}
\index{decrementar}
\index{espacio en blanco}
\end{description}
" + str + "Close window