Python: Estructuras de datos: Cadenas

Podemos definir las cadenas con comillas, simples o dobles, pero si empezamos con simples debemos acabar con simples aunque podemos mezclar:

cadena1 = 'con comillas simples'

cadena2 = "con comillas simples"

cadena3 = "mezclando comillas 'juan' sin que afecte"

cadena4 = 'mezclando al revés "Pedro" igualmente'

print(cadena1)
con comillas simples

print(cadena2)
con comillas simples

print(cadena3)
mezclando comillas 'juan' sin que afecte

print(cadena4)
mezclando al revés "Pedro" igualmente

También podemos definir cadenas de multiple líneas usando TRIPLE comillas simple o doble:

cadena1 = '''cadena con varias
    líneas de texto
    sin problemas'''

cadena2 = """y de igual manera
    con dobles comillas
    perfectamente"""

print(cadena1)

cadena con varias
líneas de texto
sin problemas

print(cadena2)

y de igual manera
con dobles comillas
perfectamente

Podemos ver como representa Python este tipo de cadenas múltiples, que además puede ser muy útil:

cadena1 = '''cadena con varias
    líneas de texto
    sin problemas'''

print(repr(cadena1))

'cadena con varias\nlíneas de texto\nsin problemas'

Cómo ver el tipo:

cadena = "192.168.1.1"

type(cadena)
str

Las cadenas funcionan como un array, empezando por cero (de izquierda a derecha) y por -1 (de derecha a izquierda):

#   1   9  2  .  1  6  8  .  1  .   1
# -----------------------------------
#   0   1  2  3  4  5  6  7  8  9  10
# -11 -10 -9 -8 -7 -6 -5 -4 -3 -2  -1

cadena = "192.168.1.1"

cadena[2]
'2'

cadena[-10]
'9'

Pero también podemos obtener porciones de la cadena, lo que se llama slicing, usando inicio (recordando que empieza desde 0) y final (no incluido, es decir que si ponemos 6 incluirá hasta el carácter 5 pero NO el 6) separados por ":" (si alguno o ambos se omiten se entiende que es el principio o final o ambos), de la siguiente forma:

cadena = "192.168.1.1"

cadena[8:]
'1.1'

cadena[0:6]
'192.16'

cadena[:7]
'192.168'

Una ventaja del slicing es que permite saltarse el indice máximo cosa que directamente nos daría un error:

cadena = "192.168.1.1"

cadena[23]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
 in ()
----> 1 cadena[23]

IndexError: string index out of range

cadena[7:23]
'.1.1'

Python NO permite asigna valores ni a un indice ni a un slice, pero podemoa hacer ciertos apaños, como por ejemplo:

cadena = "192.168.3.7"

cadena[8]
'3'

cadena[8] = 4
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in ()
----> 1 cadena[8] = 4

TypeError: 'str' object does not support item assignment

cadena = cadena[:8] + "4" + cadena[9:]

cadena
'192.168.4.7'

Como cualquier cadena puede contener caracteres especiales como /n que representa nueva línea, pero si queremos que la cadena muestre /n siempre podemos escapar los caracteres especiales \/n o podemos indicar que ignore los caracteres especiales anteponiendo una r antes de la primera comilla, veamos unos ejemplos:

cadena = "esto es un PATH de Windows c:\windows\nuevo\trabajo\fichero1"

cadena
'esto es un PATH de Windows c:\\windows\nuevo\trabajo\fichero1'

print(cadena)
esto es un PATH de Windows c:\windows
uevo	rabajo
              ichero1

cadena = r"esto es un PATH de Windows c:\windows\nuevo\trabajo\fichero1"

cadena
'esto es un PATH de Windows c:\\windows\\nuevo\\trabajo\\fichero1'

print(cadena)
esto es un PATH de Windows c:\windows\nuevo\trabajo\fichero1

Para suprimir todos los caracteres de espacio, tabuladores, saltos de líneas, etc, del principio y final de una cadena, podemos usar los métodos .strip, .lstrip y .rstrip, con ejemplos se ve mejor:

cadena = "     texto de ejemplo, con espacios\t tabulación y saltos de línea\n\t\n"

cadena.strip()
'texto de ejemplo, con espacios\t tabulación y saltos de línea'

cadena.lstrip()
'texto de ejemplo, con espacios\t tabulación y saltos de línea\n\t\n'

cadena.rstrip()
'     texto de ejemplo, con espacios\t tabulación y saltos de línea'

print(cadena.strip())
texto de ejemplo, con espacios 	 tabulación y
 saltos de línea

Para dividir cadenas según un patron podemos usar str.split(sep=None, maxsplit=-1), por defecto usa espacios en blanco como separador y el separador pude ser más de un carácter.

Siempre se devuelve una lista con las divisiones que haya realizado aunque solo sea una (es decir la misma cadena).Como segundo parámetro podemos indicar el número máximo de divisiones que debe hacer (número de veces que cuenta el separador).

También tenemos el mismo método pero que empieza por el final str.rsplit(sep=None, maxsplit=-1).

cadena = "192.168.1.3"

cadena.split()
['192.168.1.3']

cadena.split('.')
['192', '168', '1', '3']

cadena.split('.', 2)
['192', '168', '1.3']

cadena.split('.', 2)
['192', '168', '1.3']

cadena.rsplit('.', 2)
['192.168', '1', '3']

cadena.split('.')[3]
'3'

cadena.split('.1')
['192', '68', '.3']

cadena.split('192')
['', '.168.1.3']

Si lo que queremos es dividir líneas (por saltos de línea \n) podemos usar str.splitlines([keepends])

cadena = """esto es una cadena
de varias líneas
y queremos solo
dividir líneas"""

cadena.split()

['esto',
 'es',
 'una',
 'cadena',
 'de',
 'varias',
 'líneas',
 'y',
 'queremos',
 'solo',
 'dividir',
 'líneas']

cadena.splitlines()
['esto es una cadena', 'de varias líneas', 'y queremos solo', 'dividir líneas']

cadena.split("\n")
['esto es una cadena', 'de varias líneas', 'y queremos solo', 'dividir líneas']

Su formato es: separador.join(elementos), el separador es una cadena (str) y puede ser de 1 o más caracteres y elementos por lo general será una lista a unir con el separador. El valor de vuelto es una cadena (str).

ip = '192.168.1.2'

elementos = ip.split('.')

elementos
['192', '168', '1', '2']

ip1 = '.'.join(elementos)

ip1
'192.168.1.2'

ip2 = '.:.'.join(elementos)

ip2
'192.:.168.:.1.:.2'

Un potente método es str.replace(old, new[, count]) que reemplaza old (uno o más caracteres) por new (uno o más caracteres), por defecto todas las veces que aparezca, a menos que le indiquemos cuentas veces máximo debe reemplazar con count.

"Hola mundo, adios mundo".replace(' mundo','')
'Hola, adios'

"Hola mundo, adios mundo".replace(' mundo','',1)
'Hola, adios mundo'

"Hola mundo, adios mundo".replace('o','0')
'H0la mund0, adi0s mund0'

Tenemos varios métodos para gestionar las mayúsculas y minúsculas que se ven mejor en ejemplos:

Todos los métodos permiten dos parámetros más indicando desde que posición inicial hasta que posición final, por ejemplo: str.find(sub[, start[, end]]).

# Devuelve la cadena con todos sus caracteres a mayúscula
"Hola Mundo".upper()
'HOLA MUNDO'

#Devuelve la cadena con todos sus caracteres a minúscula
"Hola Mundo".lower()
'hola mundo'

# Devuelve la cadena con su primer carácter en mayúscula
"hola mundo".capitalize()
'Hola mundo'

# Devuelve la cadena con el primer carácter de cada palabra en mayúscula
"hola mundo".title()
'Hola Mundo'

# Devuelve True si la cadena es todo minúsculas
"Hola mundo".islower()
False

"Hola mundo".lower().islower()
True

# Devuelve True si la cadena es todo mayúsculas
"Hola mundo".isupper()
False

"Hola mundo".upper().isupper()
True

# Devuelve True si la primera letra de cada palabra es mayúscula
"Hola Mundo".istitle()
True

Para algunos idiomas como el alemán, en vez de usar str.lower() debemos usar str.casefold() que gestiona mejor ciertos caracteres especiales.

Tenemos varios métodos para averiguar la posición (índice) de palabras que se ven mejor en ejemplos:

# Devuelve el índice en el que aparece la subcadena (-1 si no aparece)
"Hola mundo, adios mundo".find('mundo')
5-----^

"Hola mundo, adios mundo".find('mundos')
-1


# Devuelve el índice en el que aparece la subcadena, empezando por el final
"Hola mundo, adios mundo".rfind('mundo')
18-----------------^

"Hola mundo, adios mundo".rfind('mundos')
-1


# igual que find pero si no se encuentra produce una excepción
"Hola mundo, adios mundo".index('mundo')
5-----^

"Hola mundo, adios mundo".index('mundo', 6)
18-----------------^

"Hola mundo, adios mundo".index('mundos')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
 in ()
----> 1 "Hola mundo, adios mundo".index('mundos')

ValueError: substring not found


# igual que rfind pero si no se encuentra produce una excepción
"Hola mundo, adios mundo".rindex('mundo')
18

"Hola mundo, adios mundo".rindex('mundos')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
 in ()
----> 1 "Hola mundo, adios mundo".rindex('mundos')

ValueError: substring not found

Para algunos idiomas como el alemán, en vez de usar str.lower() debemos usar str.casefold() que gestiona mejor ciertos caracteres especiales.

Podemos comprobar si el contenido de la cadena son solo números (str.isdigit()), si es alfanumérico (str.isalnum()), si todo son letras (str.isalpha()), si solo contiene espacios (str.isspace()), veamos unos ejemplos:

También hay 2 métodos muy potentes para comprobar si una cadena empieza (str.startswith(prefix[, start[, end]])) o si termina (str.endswith(suffix[, start[, end]])) por cierta cadena.

"12343".isdigit()
True

# el espacio, coma, etc no son alfanuméricos
"Hola mundo, adios mundo 3 2 1".isalnum()
False

"Holamundoadiosmundo321".isalnum()
True


"12343".isdecimal()
True

"12343".isnumeric()
True


# 1/2 es numérico
'½'.isnumeric()
True

# 2 elevado al cubo es númerico
'2³'.isnumeric()
True

# devuelve True solo si TODOS los caracteres son espacio
"  -  ".isspace()
False


"Hola mundo".startswith("Hola")
True

"Hola mundo".endswith("mundo")
True

Tenemos varios métodos para gestionar caracteres (por defecto el espacio) al principio y final, veamos unos ejemplos:

"   Hola mundo     ".strip()
'Hola mundo'

"---Hola mundo     ".lstrip("-")
'Hola mundo     '

"   Hola mundo     ".lstrip()
'Hola mundo     '

"   Hola mundo     ".rstrip()
'   Hola mundo'

También puede ser interesante cambiar los tabuladores pro espacios (por defecto 8 espacios).

"\tHola\tmundo".expandtabs()
'        Hola    mundo'

"\tHola\tmundo".expandtabs(4)
'    Hola    mundo'

Tenemos varios métodos para alinear cadenas (por defecto rellenando con espacios) y también dos métodos exclusivos para números:

"titulo".center(12)
'   titulo   '

"titulo".center(12,"-")
'---titulo---'

"titulo".ljust(12)
'titulo      '

"titulo".ljust(12,"-")
'titulo------'

"titulo".rjust(12)
'      titulo'

"titulo".rjust(12,"-")
'------titulo'

"42".zfill(5)
'00042'

"-42".zfill(5)
'-0042'

En las cadenas NO tenemos el métdodo reverse pero podemos hacer un pequeño truco para realizarlo:

cadena = "Hola mundo, adios mundo"

lista = list(cadena)

lista.reverse()

cadena = "".join(lista)

cadena
'odnum soida ,odnum aloH'

Más información en: cadenas y métodos de cadenas

Retro

Lugares

Redes

Sistemas

Varios