Strings, índices y slicing
Cómo leer, cortar y transformar texto sin mutarlo ni perder caracteres por el camino
Un string es una secuencia inmutable de caracteres. Aprenderás a acceder a sus posiciones, cortarlo con start, stop y step, transformarlo con métodos y unir o separar texto para procesar mensajes, correos y datos reales.
- Explicar por qué un string es inmutable y qué consecuencias tiene
- Acceder a caracteres con índices positivos y negativos sin salirte del rango
- Escribir slices con inicio, fin y salto, incluido el recorrido inverso
- Usar los métodos más habituales y distinguir cuáles devuelven una cadena nueva
- Construir mensajes con f-strings y procesar texto con split y join
Antes necesitas: Variables y tipos de datos · Bucles: while, for y control de iteraciones
En esta lección
- ¿Qué es un string?
- ¿Para qué sirve?
- ¿Cómo funciona por dentro?
- Sintaxis: comillas, escapes y f-strings
- Ejemplo básico: leer posiciones
- Ejemplo intermedio: normalizar un correo
- Caso práctico: interpretar un mensaje de chat
- Visualización: índices, slicing y recorrido
- Errores comunes
- Buenas prácticas
- Ejercicios
- Soluciones explicadas
- Resumen
- Evaluación
Hasta ahora has guardado números y textos en variables, pero apenas los has manipulado. La mayor parte de lo que un programa recibe del exterior llega como texto: un mensaje de chat, una línea de CSV, el nombre de un archivo. Si no sabes cortarlo y limpiarlo, no puedes convertirlo en datos útiles.
En esta lección vas a aprender a ver un string como lo que realmente es: una secuencia ordenada de caracteres con posiciones numeradas. Esa idea, que parece simple, es la que explica los índices, el slicing, los métodos y hasta los errores que verás cuando algo se sale de rango.
¿Qué es un string?
Un string o cadena de texto es una secuencia ordenada e inmutable de caracteres. Se representa con el tipo str y se escribe entre comillas simples o dobles: "hola" y 'hola' son el mismo valor. Imagina un collar de cuentas: cada cuenta es un carácter y puedes señalar la tercera sin desmontarlo.
Inmutable significa que el contenido de una cadena no cambia nunca. Si escribes saludo[0] = "H", Python lanza un TypeError: esa posición no se puede reasignar. Lo que sí puedes hacer es crear otra cadena y apuntar la variable hacia ella. Distinguir entre cambiar la variable y mutar el objeto será clave con las listas.
¿Para qué sirve?
Cualquier tarea que implique leer, validar o presentar información escrita termina usando strings. Estos son casos que aparecerán una y otra vez en el curso y en el trabajo real:
- Procesar mensajes: separar el comando de sus argumentos en un bot de chat y normalizar mayúsculas.
- Leer datos tabulares: cada línea de un CSV es un string que hay que dividir por comas y convertir al tipo adecuado.
- Limpiar entradas: correos con mayúsculas mezcladas o nombres con espacios al inicio.
- Preparar texto para NLP: pasar a minúsculas, quitar puntuación y separar en palabras antes de contar frecuencias.
- Generar informes y rutas: componer mensajes con f-strings o nombres como
resultados_2026.csv.
¿Cómo funciona por dentro?
CPython almacena el texto como una secuencia contigua de puntos de código Unicode. Gracias a esa contigüidad, acceder a una posición concreta mediante s[i] es una operación de coste constante: el intérprete calcula dónde empieza la cadena y salta directamente a la posición pedida. No tiene que recorrer los caracteres anteriores.
Cada carácter ocupa una posición, no un byte. len("café") devuelve 4, aunque la é ocupe dos bytes en UTF-8, y un emoji habitual cuenta como un carácter. Para tamaños en bytes usarás s.encode("utf-8"), algo que aparecerá al leer archivos. Por ahora quédate con que Python indexa caracteres.
Un slice no es una vista: construye una cadena nueva con los caracteres seleccionados, así que cuesta tiempo proporcional a lo que copias. Concatenar con + dentro de un bucle es aún más caro, porque en cada vuelta se copia todo lo anterior y el coste crece de forma cuadrática.
| Operación | Ejemplo | Coste | Qué ocurre |
|---|---|---|---|
| Índice | s[3] | O(1) | Devuelve el carácter de esa posición |
| Slice | s[2:7] | O(k) | Copia los k caracteres seleccionados |
| Longitud | len(s) | O(1) | La longitud se guarda con el objeto |
| Búsqueda | s.find("x") | O(n) | Recorre hasta encontrar o llegar al final |
| Concatenar en bucle | s += trozo | O(n²) | Crea y copia una cadena nueva cada vez |
Sintaxis: comillas, escapes y f-strings
Elige comillas simples o dobles según el contenido: si el texto lleva apóstrofes, usa dobles. Las comillas triples permiten varias líneas sin \n. La barra invertida introduce caracteres especiales, y una r crea una cadena raw, donde no se interpretan.
# Comillas simples y dobles son equivalentes
saludo = 'Hola'
otro = "Hola"
# Escapes: salto de línea, tabulador y comilla
mensaje = "Primera línea\nSegunda línea"
con_comilla = 'Dijo: "hola"'
# Varias líneas con comillas triples
poema = """Rima LIII
Volverán las oscuras golondrinas"""
# Cadena raw: la barra es literal
ruta = r"C:\datos\nuevo.csv"
# f-string: inserta expresiones dentro de llaves
precio = 120
print(f"Total con IGV: {precio * 1.18:.2f}")\nsalta de línea,\tinserta un tabulador y\\escribe una barra invertida.- Las comillas triples
"""..."""conservan los saltos de línea que escribas dentro. - Una
fdelante de las comillas activa la interpolación:f"Hola, {nombre}". - Dentro de las llaves de una f-string cabe cualquier expresión, no solo un nombre de variable.
- Para escribir una llave literal en una f-string, duplícala:
f"{{esto no se evalúa}}".
Ejemplo básico: leer posiciones
nombre = "Ada"
apellido = "Lovelace"
nombre_completo = nombre + " " + apellido
inicial = nombre_completo[0]
print(nombre_completo)
print(f"Inicial: {inicial} | Longitud: {len(nombre_completo)}")
print(nombre_completo[-1])Las dos primeras líneas guardan los textos. En la tercera, el operador + une tres cadenas y produce una nueva; el espacio del medio es un string de un solo carácter. En la cuarta, nombre_completo[0] pide la posición cero, que es "A": Python empieza a contar en cero, igual que los índices de un vector.
La quinta línea imprime la cadena. La sexta usa una f-string con inicial y len(nombre_completo); la longitud es 12, porque hay doce caracteres contando el espacio. La última línea usa el índice -1, el último carácter; con [-2] obtendrías "c".
Ejemplo intermedio: normalizar un correo
Las entradas reales casi nunca llegan limpias. Supón que un formulario entrega " Ada.Lovelace@Example.COM ". Conviene quitar los espacios de los extremos, pasar a minúsculas y separar la parte local del dominio. Observa cómo se encadenan los métodos:
entrada = " Ada.Lovelace@Example.COM "
correo = entrada.strip().lower()
usuario, dominio = correo.split("@")
print(correo)
print(usuario.replace(".", "_"))
print(dominio.endswith(".com"))strip() elimina espacios y saltos de línea de ambos extremos, pero no los del interior. lower() pasa a minúsculas. Como cada método devuelve una cadena, se encadenan de izquierda a derecha: primero limpiar, luego normalizar. El resultado es "ada.lovelace@example.com".
split("@") corta la cadena por el arroba y devuelve una lista de dos elementos. La asignación usuario, dominio = ... desempaqueta esa lista: exige exactamente dos valores y falla si hay más o menos, lo que aquí funciona como validación implícita. Después, replace(".", "_") sustituye todos los puntos del usuario, y endswith(".com") comprueba el final del dominio y devuelve un booleano.
Caso práctico: interpretar un mensaje de chat
Un bot recibe mensajes con la forma /clima Lima Este 2: una barra, un comando, una ciudad que puede tener varias palabras y un número de días. El programa debe extraer cada parte. Este es el tipo de análisis que hay que hacer antes de llamar a cualquier API.
mensaje = "/clima Lima Este 2"
partes = mensaje.strip().split()
comando = partes[0]
if comando.startswith("/"):
comando = comando[1:]
ciudad = " ".join(partes[1:-1])
dias = int(partes[-1])
print(f"Comando: {comando}")
print(f"Ciudad: {ciudad} | Días: {dias}")split() sin argumentos trata cualquier bloque de espacios como separador y descarta los vacíos. partes[0] es "/clima"; el slice [1:] elimina la barra y deja "clima". Para la ciudad se usa partes[1:-1], que excluye los extremos, y join las vuelve a unir con espacio para no perder "Lima Este". El último elemento se convierte a entero; con letras, int lanzaría ValueError.
Visualización: índices, slicing y recorrido
Un slice se escribe cadena[inicio:fin:salto]. El inicio es la primera posición que quieres; el fin es exclusivo, es decir, el corte se detiene justo antes de esa posición; y el salto indica cuántas posiciones avanzar. Si omites inicio, empieza en el borde correspondiente; si omites fin, llega hasta el otro borde. Un salto negativo recorre la cadena de derecha a izquierda.
cadena[6:1:-2]='gec'La cadena abcdefgh tiene índices 0 a 7. Con inicio 6 se empieza en 'g'; el salto -2 visita 6, 4 y 2; el fin 1 es exclusivo, así que el recorrido se detiene antes de llegar a la posición 1 y no incluye la 0. Resultado: 'gec'.
Haz clic en un carácter para fijar el inicio; con Shift+clic fijas el fin. Ajusta el salto para ver el recorrido.
Sigue el recorrido: se toma el índice 6 (g), se resta 2 y se toma el 4 (e), se resta 2 y se toma el 2 (c). El siguiente sería 0, pero con salto negativo el recorrido se detiene cuando el índice es menor o igual que el fin; como 0 <= 1, termina y el resultado es "gec". Con fin -1, el 0 entraría y obtendrías "geca".
s = "abcdefgh"
print(s[2:5])
print(s[:3])
print(s[-2:])
print(s[::-1])
print(s[6:1:-2])s[2:5] toma las posiciones 2, 3 y 4 y produce "cde". s[:3] equivale a s[0:3] y da "abc". s[-2:] empieza dos posiciones antes del final: "gh". s[::-1] recorre con salto -1 y devuelve "hgfedcba". La última línea confirma "gec".
texto = " Hola, mundo "limpio = texto.strip()inicial = limpio[0]palabras = limpio.split()unido = "-".join(palabras)print(unido.upper())texto con dos espacios a cada lado. Los espacios también son caracteres y ocupan posiciones.—
Avanza paso a paso: observa la línea resaltada, las variables y la salida.
Errores comunes
| Mensaje o comportamiento | Por qué ocurre | Cómo se arregla |
|---|---|---|
IndexError: string index out of range | La posición no existe | Comprueba len(s) o usa un slice |
TypeError: 'str' object does not support item assignment | Intentaste modificar una posición | Crea una cadena nueva con s[:i] + nuevo + s[i+1:] |
| Un método parece no hacer nada | No guardaste su valor de retorno | Asigna el resultado: s = s.strip() |
TypeError: can only concatenate str (not "int") to str | Sumaste texto y número | Convierte con str(n) o usa una f-string |
El slice devuelve "" | Inicio y fin no dejan caracteres entre ellos | Revisa el orden: fin debe superar a inicio |
s = "casa"
s[0] = "C"
print(s)s = "casa"
s = "C" + s[1:]
print(s)Los strings son inmutables: no admiten asignación por índice. La alternativa es construir otra cadena combinando la parte anterior, el carácter nuevo y la parte posterior. Para una sola letra, `s.replace("c", "C", 1)` también sirve.
Cuando un slice no selecciona nada devuelve la cadena vacía, sin excepción. Es cómodo para código defensivo, pero puede ocultar un error de lógica: si esperabas "cde" y obtienes "", revisa el orden de los índices.
Buenas prácticas
- Usa f-strings para construir mensajes: son más legibles y rápidas que concatenar con
+ystr(). - Para unir muchos fragmentos, acumula en una lista y aplica
"".join(lista)una sola vez. - Normaliza al principio:
strip()ylower()evitan fallos por un espacio o una mayúscula. - Prefiere
startswithyendswitha cortar con slices para comprobar un extremo. - Los métodos devuelven cadenas nuevas:
s.strip()sin asignación no hace nada visible. - Usa comillas triples solo para texto multilínea; el resto se lee mejor en una línea.
s = "Hola"
s = s.lower()
parte = s[1:3]
print(f"{parte} {len(s)}")#include <cctype>
#include <iostream>
#include <string>
int main() {
std::string s = "Hola";
for (char& c : s) c = static_cast<char>(std::tolower(c));
std::string parte = s.substr(1, 2);
std::cout << parte << " " << s.size() << std::endl;
return 0;
}En Python `lower()` devuelve una cadena nueva; en C++ hay que recorrer y modificar el `std::string`, que sí es mutable. El slice `s[1:3]` equivale a `substr(1, 2)`: en C++ el segundo argumento es la cantidad de caracteres, no el índice final.
Ejercicios
Iniciales y vocales
"Ada King Lovelace". Muestra sus iniciales unidas por puntos (sin punto final) y cuenta cuántas vocales contiene el nombre, ignorando mayúsculas. Resuélvelo con un bucle sobre la cadena y un contador.Pista
Convierte a minúsculas antes de contar y comprueba si cada carácter pertenece a la cadena "aeiou" con el operador in.
s = "abcdefgh" print(s[:]) # debe mostrar cdef print(s[]) # debe mostrar h print(s[]) # debe mostrar a
El fin del slice es exclusivo: para incluir la f hay que escribir 6. El último índice también se escribe con un número negativo.
Nombre de usuario
" Ada King Lovelace ", genera un usuario con la forma a.lovelace: la inicial del primer nombre, un punto y el último apellido, todo en minúsculas y sin espacios sobrantes. Muestra también el correo corporativo añadiendo @aula.ml.Pista
Limpia, pasa a minúsculas y usa split() para obtener las partes. El último apellido está en el índice -1.
Soluciones explicadas
En el primer ejercicio, nombre[0] solo funciona con un nombre. Al dividir en palabras obtienes una estructura iterable y el mismo código sirve para dos o cinco nombres. La parte de las vocales muestra que un string se recorre con for igual que una lista: cada iteración entrega un carácter.
En el segundo, el orden importa: strip() antes de split() evita palabras vacías y lower() garantiza un formato uniforme. No hay ningún bucle explícito porque los métodos recorren por dentro. Esa es la señal de que empiezas a pensar en operaciones sobre secuencias.
Resumen
- Un string es una secuencia ordenada e inmutable; sus métodos devuelven cadenas nuevas.
- Los índices empiezan en 0; los negativos cuentan desde el final (
-1es el último). - El slice
s[a:b:c]incluyea, excluyeby avanzac; con salto negativo va hacia atrás. - Un slice fuera de rango no lanza error: se recorta a los límites disponibles.
strip,lower,replace,startswithyfindresuelven la limpieza habitual.splitsepara en una lista yjoinune una lista con el separador que elijas.- Las f-strings interpolan expresiones y admiten formato, como
:.2f.
Evaluación
¿Qué devuelve "Python"[1:4]?
Después de s = "hola" y s.upper(), ¿qué contiene s?
¿Cuántos elementos produce "a,b,,c".split(",")?
¿Ya lo entendiste?
Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.