Strings a fondo
En esta guía (14)
Ya venís usando strings desde la primera lección. En esta vas a verlos como lo que son, una secuencia de caracteres, y vas a conocer los métodos que resuelven el 90% del trabajo con texto: cambiar mayúsculas, limpiar espacios, buscar y reemplazar, partir un texto en pedazos y volver a unirlo, y formatear salidas prolijas.
Un string es una secuencia
Todo lo que aprendiste de índices y slicing en listas funciona con strings:
palabra = "Python"
print(palabra[0]) # P
print(palabra[-1]) # n
print(palabra[1:4]) # yth
print(palabra[::-1]) # nohtyP
print(len(palabra)) # 6
print("th" in palabra) # True
Con strings, in busca subtextos, no solo caracteres sueltos.
Los strings son inmutables
A diferencia de una lista, no podés cambiar un carácter de un string:
>>> palabra = "Python"
>>> palabra[0] = "J"
TypeError: 'str' object does not support item assignment
Todas las operaciones que "modifican" un string en realidad devuelven uno nuevo. Si querés conservar el cambio, tenés que asignarlo:
nombre = "ana"
nombre.upper() # devuelve "ANA", pero nadie lo guarda
print(nombre) # ana
nombre = nombre.upper() # ahora sí
print(nombre) # ANA
Esto es lo más importante de la lección: los métodos de string nunca cambian el original.
Mayúsculas y minúsculas
texto = "hola MUNDO, qué tal"
print(texto.upper()) # HOLA MUNDO, QUÉ TAL
print(texto.lower()) # hola mundo, qué tal
print(texto.title()) # Hola Mundo, Qué Tal
print(texto.capitalize()) # Hola mundo, qué tal
Un uso muy común: comparar sin que importen las mayúsculas.
respuesta = "SI"
if respuesta.lower() == "si":
print("Confirmado")
Confirmado
Limpiar espacios
Cuando el texto viene del usuario o de un archivo, suele traer espacios de más:
sucio = " Mendoza \n"
print(f"[{sucio.strip()}]") # [Mendoza]
print(f"[{sucio.lstrip()}]") # quita solo a la izquierda
print(f"[{sucio.rstrip()}]") # quita solo a la derecha
[Mendoza]
[Mendoza
]
[ Mendoza]
strip() saca espacios, tabs y saltos de línea de los extremos (no del medio). También le podés pasar qué caracteres sacar: "--hola--".strip("-") da "hola".
Acostumbrate a hacer input(...).strip(): el usuario puede tipear un espacio sin darse cuenta.
Buscar y reemplazar
frase = "el gato y el perro y el loro"
print(frase.count("el")) # 3
print(frase.find("perro")) # 13 (posición donde empieza)
print(frase.find("vaca")) # -1 (no está)
print(frase.startswith("el")) # True
print(frase.endswith(".txt")) # False
print(frase.replace("el", "un")) # un gato y un perro y un loro
print(frase.replace("el", "un", 1)) # un gato y el perro y el loro
replace reemplaza todas las apariciones, salvo que le pases cuántas como tercer argumento. Sirve, por ejemplo, para aceptar coma decimal:
texto = "12,5"
numero = float(texto.replace(",", "."))
print(numero * 2) # 25.0
Preguntar qué tiene un texto
Estos métodos devuelven True o False:
print("2026".isdigit()) # True: solo dígitos
print("abc".isalpha()) # True: solo letras
print("abc123".isalnum()) # True: letras y/o dígitos
print(" ".isspace()) # True: solo espacios
print("Hola".isupper()) # False
print("hola".islower()) # True
Ojo: "".isdigit() es False (un texto vacío no tiene dígitos), y "-5".isdigit() también es False por el signo.
split y join: partir y unir
split parte un string y devuelve una lista:
linea = "Ana,28,Córdoba"
partes = linea.split(",")
print(partes) # ['Ana', '28', 'Córdoba']
nombre, edad, ciudad = partes
print(f"{nombre} tiene {int(edad)} años") # Ana tiene 28 años
frase = " muchas palabras sueltas "
print(frase.split()) # ['muchas', 'palabras', 'sueltas']
Sin argumentos, split() corta por cualquier cantidad de espacios y descarta los vacíos. Con un separador, corta exactamente ahí.
join hace lo inverso: une una lista de strings usando un separador. Se escribe al revés de lo que uno espera, el separador primero:
palabras = ["hola", "que", "tal"]
print(" ".join(palabras)) # hola que tal
print("-".join(palabras)) # hola-que-tal
print("".join(palabras)) # holaquetal
join solo acepta strings. Si tenés números, convertilos primero: ", ".join(str(n) for n in [1, 2, 3]) da "1, 2, 3". (Esa expresión dentro de los paréntesis es como una list comprehension sin corchetes; para join funciona igual.)
Con splitlines() partís un texto de varias líneas en una lista de líneas:
texto = "primera\nsegunda\ntercera"
print(texto.splitlines()) # ['primera', 'segunda', 'tercera']
Caracteres especiales y strings de varias líneas
Dentro de un string, la barra invertida \ arma secuencias de escape:
| Secuencia | Significa |
|---|---|
\n | salto de línea |
\t | tabulación |
\\ | una barra invertida |
\" | comilla doble dentro de un string con comillas dobles |
print("Nombre:\tAna\nEdad:\t28")
Nombre: Ana
Edad: 28
Para textos largos, las triples comillas permiten escribir varias líneas tal cual:
mensaje = """Hola,
este mensaje tiene
varias líneas."""
print(mensaje)
Hola,
este mensaje tiene
varias líneas.
Si querés que las barras invertidas no se interpreten (útil en rutas de Windows), anteponé una r: r"C:\nueva\carpeta" se guarda literalmente.
Formato a fondo
En la lección 2 viste lo básico de las f-strings. Estos son los formatos que más se usan para armar salidas prolijas:
producto = "Café"
precio = 4500.5
stock = 7
print(f"|{producto:<10}|") # alineado a la izquierda en 10 lugares
print(f"|{producto:>10}|") # a la derecha
print(f"|{producto:^10}|") # centrado
print(f"|{producto:*^10}|") # centrado, rellenando con *
print(f"|{stock:03d}|") # entero con ceros a la izquierda
print(f"|{precio:>10.2f}|") # 10 lugares, 2 decimales, a la derecha
print(f"|{precio:,.2f}|") # separador de miles
|Café |
| Café|
| Café |
|***Café***|
|007|
| 4500.50|
|4,500.50|
El formato general es {valor:relleno alineación ancho .decimales tipo}, y todas las partes son opcionales. Con eso podés armar tablas:
productos = [("Yerba", 3200, 12), ("Azúcar", 1100.5, 0), ("Café molido", 4500, 7)]
print(f"{'Producto':<12}{'Precio':>10}{'Stock':>7}")
print("-" * 29)
for nombre, precio, stock in productos:
print(f"{nombre:<12}{precio:>10.2f}{stock:>7}")
Producto Precio Stock
-----------------------------
Yerba 3200.00 12
Azúcar 1100.50 0
Café molido 4500.00 7
Un truco para depurar: f"{variable=}" muestra el nombre y el valor.
total = 1250
print(f"{total=}") # total=1250
Limpieza de texto: un ejemplo completo
Juntando todo: tenés nombres cargados a mano, con espacios y mayúsculas desprolijas, y querés normalizarlos.
crudos = [" ana PÉREZ", "bruno gómez ", "CARLA díaz", " ", "diego ruiz"]
limpios = []
for nombre in crudos:
nombre = " ".join(nombre.split()) # colapsa espacios repetidos y recorta
if nombre: # descarta los que quedaron vacíos
limpios.append(nombre.title())
print(limpios)
['Ana Pérez', 'Bruno Gómez', 'Carla Díaz', 'Diego Ruiz']
" ".join(texto.split()) es un truco muy usado: split() separa por cualquier cantidad de espacios y join vuelve a unir con uno solo.
Errores comunes
- Llamar a un método y no guardar el resultado.
texto.strip()solo no cambiatexto. Hacétexto = texto.strip(). - Intentar cambiar un carácter con
texto[0] = .... Los strings son inmutables: armá uno nuevo, por ejemplo"J" + texto[1:]. - Usar
joinal revés. Esseparador.join(lista), nolista.join(separador). - Pasarle números a
join. DaTypeError: sequence item 0: expected str instance, int found. Convertí cada elemento constr(). - Comparar textos sin normalizar.
"Si" == "si"esFalse. Usá.strip().lower()en los dos lados. - Confiar en
isdigit()para decimales o negativos."3.5".isdigit()y"-2".isdigit()danFalse.
Practicá
- Pedí una frase y decí si es un palíndromo (se lee igual al derecho y al revés), sin importar mayúsculas ni espacios. Por ejemplo, "Anita lava la tina" lo es.
- Tenés el texto de configuración
"host=localhost;puerto=8080;modo=prueba". Convertilo en el diccionario{'host': 'localhost', 'puerto': '8080', 'modo': 'prueba'}. - Escribí un programa que pida un nombre de usuario y lo valide: entre 4 y 12 caracteres, solo letras y números, y que no empiece con un número. Mostrá un mensaje distinto para cada problema.
- Dada la lista
items = [("Notebook", 1, 850000), ("Mouse", 2, 12500.5), ("Monitor", 1, 210000)](producto, cantidad, precio unitario), imprimí un ticket alineado con el subtotal de cada línea y el total al final, con separador de miles y dos decimales.
Soluciones
Ejercicio 1:
frase = input("Frase: ")
normalizada = "".join(frase.lower().split())
if normalizada == normalizada[::-1]:
print("Es palíndromo")
else:
print("No es palíndromo")
Frase: Anita lava la tina
Es palíndromo
Ejercicio 2:
texto = "host=localhost;puerto=8080;modo=prueba"
config = {}
for par in texto.split(";"):
clave, valor = par.split("=")
config[clave] = valor
print(config) # {'host': 'localhost', 'puerto': '8080', 'modo': 'prueba'}
Ejercicio 3:
usuario = input("Usuario: ").strip()
if not 4 <= len(usuario) <= 12:
print("Tiene que tener entre 4 y 12 caracteres")
elif not usuario.isalnum():
print("Solo puede tener letras y números")
elif usuario[0].isdigit():
print("No puede empezar con un número")
else:
print(f"Usuario '{usuario}' válido")
Usuario: 9lives
No puede empezar con un número
Como las condiciones van en orden, cuando llegás a usuario[0] ya sabés que el texto tiene al menos 4 caracteres, así que el índice 0 existe.
Ejercicio 4:
items = [("Notebook", 1, 850000), ("Mouse", 2, 12500.5), ("Monitor", 1, 210000)]
total = 0
for producto, cantidad, precio in items:
subtotal = cantidad * precio
total += subtotal
print(f"{producto:<10}{cantidad:>3} x {precio:>12,.2f}{subtotal:>15,.2f}")
print("-" * 43)
print(f"{'TOTAL':<28}{total:>15,.2f}")
Notebook 1 x 850,000.00 850,000.00
Mouse 2 x 12,500.50 25,001.00
Monitor 1 x 210,000.00 210,000.00
-------------------------------------------
TOTAL 1,085,001.00
Resumen
- Un string es una secuencia: índices, slicing,
leneinfuncionan como en las listas. - Los strings son inmutables: los métodos devuelven un string nuevo y hay que guardarlo.
upper,lower,titlecambian mayúsculas;striplimpia los extremos;replacereemplaza;findycountbuscan.isdigit,isalpha,isalnumvalidan contenido.splitparte un texto en una lista;separador.join(lista)une una lista de strings.\ny\tson salto de línea y tabulación; las triples comillas permiten texto de varias líneas.- En las f-strings,
:<10,:>10,:^10,:.2fy:,controlan alineación, decimales y separador de miles.