Semestre 02, 2026
Se requiere saber si el correo que escribió el usuario tiene el símbolo arroba.
correo = input("Correo: ")
# ¿y ahora qué?
Con lo visto hasta ahora el texto solo se puede guardar e imprimir. Hace falta una forma de medirlo, recorrerlo, buscar dentro de él y transformarlo.
Un string es una secuencia ordenada de caracteres. Cada carácter ocupa una posición numerada que se llama índice.
nombre = "María"
mensaje = 'Hola, mundo'
La palabra Python guardada en una variable se ve así por dentro.
| Carácter | P | y | t | h | o | n |
|---|---|---|---|---|---|---|
| Índice | 0 | 1 | 2 | 3 | 4 | 5 |
Al ser una secuencia, un string se puede medir, indexar, cortar y recorrer con un ciclo, igual que cualquier otra colección ordenada.
Python acepta ambas y el resultado es idéntico.
a = "Hola"
b = 'Hola'
La comilla que abre el string es la que lo cierra. Mezclarlas produce un error de sintaxis.
Tener dos tipos de comillas resuelve el caso en que el texto incluye una de ellas.
frase = 'Ella dijo "hola" y se fue'
otra = "No se puede, está ocupado"
Si el texto lleva comillas dobles se usan simples por fuera, y al revés.
Algunos caracteres no se pueden escribir directamente y se representan con una barra invertida.
| Secuencia | Significado |
|---|---|
| \n | Salto de línea |
| \t | Tabulación |
| \" | Comilla doble literal |
| \' | Comilla simple literal |
| \\ | Barra invertida literal |
print("Línea 1\nLínea 2")
print("Nombre:\tAna")
print("Dijo \"hola\"")
Línea 1
Línea 2
Nombre: Ana
Dijo "hola"
La barra invertida y la letra son dos caracteres en el código, pero uno solo dentro del string. Por eso len de barra n es 1.
Tres comillas permiten escribir un texto largo conservando los saltos de línea.
menu = """1. Agregar
2. Consultar
3. Salir"""
print(menu)
La función len devuelve el número de caracteres de un string.
texto = "Python"
print(len(texto)) # 6
print(len("Hola mundo")) # 10, el espacio cuenta
print(len("¡Hola!")) # 6, los signos cuentan
print(len("")) # 0, string vacío
Espacios, signos de puntuación y acentos son caracteres como cualquier otro. El string vacío existe y su longitud es cero.
Se requiere rechazar contraseñas de menos de ocho caracteres.
contrasena = input("Escribe tu contraseña: ")
if len(contrasena) < 8:
print("La contraseña es demasiado corta.")
else:
print("Contraseña aceptada.")
Cada carácter de un string tiene una posición llamada índice. La numeración empieza en cero.
| Carácter | P | y | t | h | o | n |
|---|---|---|---|---|---|---|
| Índice | 0 | 1 | 2 | 3 | 4 | 5 |
| Desde el final | -6 | -5 | -4 | -3 | -2 | -1 |
El índice se escribe entre corchetes después del string.
texto = "Python"
print(texto[0]) # P
print(texto[1]) # y
print(texto[5]) # n
Los índices negativos cuentan desde el final hacia atrás.
texto = "Python"
print(texto[-1]) # n
print(texto[-2]) # o
print(texto[-6]) # P
Permiten tomar el último carácter sin conocer la longitud del string.
texto = "Python"
print(texto[6]) # IndexError
El índice máximo es len del texto menos uno. Un string de seis caracteres llega hasta el índice cinco.
Un slice extrae una porción del string. Se escribe con el índice inicial y el final separados por dos puntos.
texto[inicio:fin]
El carácter en la posición final no se incluye.
| Expresión | Resultado | Caracteres tomados |
|---|---|---|
| texto[0:3] | Pyt | índices 0, 1 y 2 |
| texto[2:5] | tho | índices 2, 3 y 4 |
| texto[1:4] | yth | índices 1, 2 y 3 |
La cantidad de caracteres que devuelve un slice es el final menos el inicio.
texto = "Python"
print(texto[:3]) # Pyt, desde el inicio
print(texto[3:]) # hon, hasta el final
print(texto[:]) # Python, copia completa
Omitir un extremo evita tener que calcular la longitud del string.
Un tercer valor indica cada cuántos caracteres se avanza.
texto = "Python"
print(texto[::2]) # Pto, de dos en dos
print(texto[::-1]) # nohtyP, al revés
Un paso negativo recorre el string de derecha a izquierda, así que invertir un texto cabe en una sola expresión.
Se requiere obtener el usuario y el dominio de un correo conocido.
correo = "[email protected]"
print(correo[:7]) # usuario
print(correo[8:]) # uvg.edu.gt
Las posiciones están escritas a mano, por lo que el programa solo funciona con ese correo. Más adelante los métodos resuelven el caso general.
Al ser una secuencia, un string se puede recorrer con for sin necesidad de índices.
nombre = "Ana"
for letra in nombre:
print(letra)
Se imprimen A, n y a, cada una en su propia línea. La variable del ciclo recibe un carácter por vuelta.
Cuando se necesita la posición además del carácter, se recorre el rango de la longitud.
texto = "Python"
for i in range(len(texto)):
print(i, texto[i])
Si la posición no hace falta, se prefiere la primera forma porque es más corta y no puede salirse del rango.
El operador in responde si un texto aparece dentro de otro.
frase = "El cielo es azul"
print("azul" in frase) # True
print("verde" in frase) # False
print("verde" not in frase) # True
Funciona igual con un carácter y con una palabra completa, y devuelve un valor booleano que se puede usar directamente en un if.
Se requiere contar cuántas vocales tiene un texto, recorriéndolo carácter por carácter.
texto = "murciélago"
vocales = "aeiouáéíóú"
contador = 0
for letra in texto:
if letra in vocales:
contador = contador + 1
print("Vocales:", contador) # 5
Un string no se puede modificar después de creado. Ninguna operación cambia el string original.
texto = "Python"
texto[0] = "p" # TypeError
La solución no es modificar, sino armar otro string a partir del original.
texto = "Python"
nuevo = "p" + texto[1:]
print(nuevo) # python
Se toma la parte que se conserva con un slice y se concatena con la parte nueva.
nombre = "Carlos"
nombre.upper()
print(nombre) # Carlos, sin cambio
El método se ejecutó y produjo un string nuevo, pero nadie lo guardó, así que el resultado se perdió.
nombre = "Carlos"
resultado = nombre.upper()
print(resultado) # CARLOS
print(nombre) # Carlos
Todo método de string devuelve un valor que hay que asignar a una variable o usar de inmediato.
El operador más une dos strings en uno nuevo.
saludo = "Hola"
nombre = "Luis"
mensaje = saludo + ", " + nombre + "!"
print(mensaje) # Hola, Luis!
edad = 22
print("Tengo " + edad + " años") # TypeError
print("Tengo " + str(edad) + " años")
El operador más solo une strings con strings. Un número se convierte antes con la función str.
Se requiere armar una sola línea con los números del uno al cinco.
resultado = ""
for i in range(1, 6):
resultado = resultado + str(i) + " "
print(resultado) # 1 2 3 4 5
La variable empieza vacía y en cada vuelta se reasigna con su contenido anterior más la parte nueva.
El operador por repite un string la cantidad de veces indicada.
linea = "-" * 20
separador = "=-" * 10
print(linea)
print(separador)
Sirve para dibujar separadores y bordes en la salida sin escribir veinte guiones a mano.
Los operadores de igualdad funcionan con strings y comparan carácter por carácter.
print("hola" == "hola") # True
print("hola" == "Hola") # False
print("hola" != "Hola") # True
La comparación distingue mayúsculas de minúsculas, así que hola y Hola son dos strings diferentes.
Se requiere aceptar la respuesta del usuario escrita de cualquier forma.
respuesta = input("¿Continuar? (si/no): ")
if respuesta.strip().lower() == "si":
print("Continuando...")
Normalizar la entrada antes de compararla acepta SI, Si y si con espacios sobrantes, sin escribir un if por cada variante.
Un método es una función que pertenece a un tipo de dato. Se llama escribiendo un punto después del string.
texto.metodo()
Ninguno modifica el string original. Todos devuelven un valor nuevo.
texto = "hola Mundo"
print(texto.upper()) # HOLA MUNDO
print(texto.lower()) # hola mundo
print(texto.capitalize()) # Hola mundo
print(texto.title()) # Hola Mundo
capitalize pone en mayúscula solo la primera letra del texto, mientras title lo hace con la primera letra de cada palabra.
entrada = " Python "
print(entrada.strip()) # "Python"
print(entrada.lstrip()) # "Python "
print(entrada.rstrip()) # " Python"
Se aplica a toda entrada del usuario, porque un espacio invisible al final arruina cualquier comparación.
frase = "Me gusta el café con café"
print(frase.replace("café", "té"))
# Me gusta el té con té
print(frase.replace("café", "té", 1))
# Me gusta el té con café
Por defecto reemplaza todas las apariciones. Un tercer argumento limita cuántas se cambian.
texto = "El gato está en el tejado"
print(texto.find("gato")) # 3
print(texto.find("perro")) # -1
Devuelve el índice donde empieza la primera aparición, o menos uno cuando el texto no está. Nótese que menos uno no significa la última posición.
Si la posición no se va a usar, in deja el código más claro que comparar el resultado de find contra menos uno.
frase = "ana banana"
print(frase.count("a")) # 6
print(frase.count("ana")) # 2
print(frase.count("z")) # 0
Las apariciones no se traslapan. En banana hay dos veces ana solo si se cuenta la primera y luego se sigue desde donde terminó.
archivo = "informe_final.pdf"
if archivo.endswith(".pdf"):
print("Es un PDF")
if archivo.startswith("informe"):
print("Es un informe")
Reconocer extensiones de archivo, prefijos de código y dominios de correo sin calcular índices.
split separa un string en varias partes y las entrega en una lista.
frase = "manzana naranja uva"
frutas = frase.split()
print(frutas) # ['manzana', 'naranja', 'uva']
print(frutas[0]) # manzana
La lista es el tema de la siguiente clase. Por ahora basta saber que guarda varios valores y que cada uno se obtiene con un índice.
Sin argumentos separa por espacios. Con un argumento separa por el texto indicado.
fecha = "2026-04-15"
partes = fecha.split("-")
print(partes[0]) # 2026
print(partes[1]) # 04
print(partes[2]) # 15
Se requiere separar los campos de una línea que viene de un archivo.
linea = "Pedro,25,Guatemala"
datos = linea.split(",")
print(f"Nombre: {datos[0]}")
print(f"Edad: {datos[1]}")
print(f"País: {datos[2]}")
join hace lo contrario de split, pues toma varias partes y las vuelve un solo string.
palabras = ["Hola", "desde", "Python"]
print(" ".join(palabras)) # Hola desde Python
print("-".join(palabras)) # Hola-desde-Python
El separador es el string sobre el que se llama al método, y las partes van como argumento.
print("12345".isdigit()) # True, solo dígitos
print("Hola".isalpha()) # True, solo letras
print("abc123".isalnum()) # True, letras y dígitos
print(" ".isspace()) # True, solo espacios
Todos devuelven un booleano y todos son falsos para el string vacío. Un espacio hace que isalpha sea falso.
Se requiere leer una edad y evitar que el programa falle si el usuario escribe letras.
edad = input("Tu edad: ").strip()
if edad.isdigit():
print("Edad:", int(edad))
else:
print("Eso no es un número.")
Preguntar antes de convertir evita el error de ejecución que produce int con un texto que no es numérico.
Una f-string inserta el valor de una variable dentro de un texto. Se escribe poniendo una f antes de la comilla.
nombre = "Ana"
edad = 22
print(f"Hola, {nombre}. Tienes {edad} años.")
# Hola, Ana. Tienes 22 años.
Con concatenación
print("El área es " +
str(base * altura) +
" cm2")
Con f-string
print(f"El área es {base * altura} cm2")
La f-string no necesita convertir con str ni cerrar y abrir comillas, así que se lee de corrido.
Entre las llaves cabe cualquier expresión, no solo el nombre de una variable.
a = 5
b = 3
print(f"La suma de {a} y {b} es {a + b}")
print(f"El cuadrado de {a} es {a ** 2}")
print(f"En mayúsculas: {nombre.upper()}")
Después de dos puntos se indica cómo mostrar el valor.
precio = 1234.5678
print(f"Total: {precio:.2f}") # Total: 1234.57
print(f"Total: {precio:10.2f}") # alineado a 10 espacios
Mostrar dinero con dos decimales y alinear columnas en una tabla impresa en la terminal.
Se requiere leer una frase y reportar cuántos caracteres y cuántas palabras tiene, mostrarla en mayúsculas e indicar si menciona Python. Los espacios sobrantes de la entrada no deben contarse.
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
La función input siempre devuelve un string, incluso si el usuario escribe números. Lo que llega puede traer espacios al inicio o al final.
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
strip devuelve un string nuevo sin los espacios de los extremos. El resultado se guarda en otra variable porque el original no cambia.
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
Dentro de las llaves se puede llamar a una función. len cuenta los caracteres del texto ya limpio, no los de la entrada original.
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
split corta el texto en palabras y len cuenta cuántas quedaron. Se leen de adentro hacia afuera, primero el corte y luego la cuenta.
texto = input("Escribe una frase: ")
limpio = texto.strip()
print(f"Caracteres: {len(limpio)}")
print(f"Palabras: {len(limpio.split())}")
print(f"Mayúsculas: {limpio.upper()}")
print(f"Menciona Python: {'Python' in limpio}")
Una f-string también acepta métodos y comparaciones. La última línea imprime True o False según si la palabra aparece en la frase.
Para la entrada con espacios sobrantes Aprendo Python.
Caracteres: 14
Palabras: 2
Mayúsculas: APRENDO PYTHON
Menciona Python: True
Son 14 caracteres y no 18, porque strip quitó los espacios de los extremos antes de contar.
Se requiere revisar un correo escrito por el usuario. Debe contener el símbolo arroba, terminar en un dominio aceptado y, si cumple, mostrar el usuario y el dominio por separado. La entrada se normaliza antes de revisarla.
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
Los métodos se encadenan porque cada uno devuelve un string. strip actúa sobre lo que dio input y lower sobre lo que dio strip.
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
Se descarta primero el caso más grave. Sin arroba el correo no se puede dividir, así que no tiene sentido seguir revisando.
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
endswith devuelve un booleano, así que se combina con los operadores lógicos ya conocidos. La condición se cumple cuando no termina en ninguno de los dos dominios.
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
Esta línea solo se ejecuta cuando ya se sabe que hay un arroba. El corte produce dos partes, la que queda antes y la que queda después.
correo = input("Correo electrónico: ").strip().lower()
if "@" not in correo:
print("Falta el símbolo arroba")
elif not correo.endswith(".com") and not correo.endswith(".gt"):
print("Dominio no reconocido")
else:
partes = correo.split("@")
print(f"Usuario: {partes[0]}")
print(f"Dominio: {partes[1]}")
La posición cero es el usuario y la uno el dominio. A diferencia del slice escrito a mano, esto funciona con cualquier correo.
| Entrada | Salida |
|---|---|
| [email protected] | Usuario jose, dominio uvg.edu.gt |
| [email protected] | Usuario ana, dominio gmail.com |
| jose.uvg.edu.gt | Falta el símbolo arroba |
| [email protected] | Dominio no reconocido |
Probar un programa con entradas mal escritas es parte de escribirlo, no un paso opcional al final.
Se requiere recorrer una palabra y reportar cuántas vocales y cuántas consonantes tiene. Los acentos cuentan como vocales y los caracteres que no son letras se ignoran.
palabra = input("Escribe una palabra: ").lower()
vocales = "aeiouáéíóú"
total_vocales = 0
total_consonantes = 0
for letra in palabra:
if letra in vocales:
total_vocales = total_vocales + 1
elif letra.isalpha():
total_consonantes = total_consonantes + 1
print(f"Vocales: {total_vocales}")
print(f"Consonantes: {total_consonantes}")
palabra = input("Escribe una palabra: ").lower()
vocales = "aeiouáéíóú"
total_vocales = 0
total_consonantes = 0
for letra in palabra:
if letra in vocales:
total_vocales = total_vocales + 1
elif letra.isalpha():
total_consonantes = total_consonantes + 1
print(f"Vocales: {total_vocales}")
print(f"Consonantes: {total_consonantes}")
Pasar la palabra a minúsculas evita tener que listar también las vocales en mayúscula. El string de vocales hace de referencia para la comparación.
palabra = input("Escribe una palabra: ").lower()
vocales = "aeiouáéíóú"
total_vocales = 0
total_consonantes = 0
for letra in palabra:
if letra in vocales:
total_vocales = total_vocales + 1
elif letra.isalpha():
total_consonantes = total_consonantes + 1
print(f"Vocales: {total_vocales}")
print(f"Consonantes: {total_consonantes}")
Los contadores se inicializan antes del ciclo. Si se declararan dentro, se reiniciarían en cada vuelta y el resultado final sería cero o uno.
palabra = input("Escribe una palabra: ").lower()
vocales = "aeiouáéíóú"
total_vocales = 0
total_consonantes = 0
for letra in palabra:
if letra in vocales:
total_vocales = total_vocales + 1
elif letra.isalpha():
total_consonantes = total_consonantes + 1
print(f"Vocales: {total_vocales}")
print(f"Consonantes: {total_consonantes}")
El ciclo da una vuelta por carácter y no necesita índices ni la longitud de la palabra. La variable letra contiene un string de un solo carácter.
palabra = input("Escribe una palabra: ").lower()
vocales = "aeiouáéíóú"
total_vocales = 0
total_consonantes = 0
for letra in palabra:
if letra in vocales:
total_vocales = total_vocales + 1
elif letra.isalpha():
total_consonantes = total_consonantes + 1
print(f"Vocales: {total_vocales}")
print(f"Consonantes: {total_consonantes}")
El elif se evalúa solo cuando la letra no es vocal. isalpha descarta espacios, guiones y números, que no se cuentan en ningún grupo.
Para la entrada murciélago.
Vocales: 5
Consonantes: 5
La vocal acentuada se cuenta porque está en el string de referencia. Sin ella el resultado sería cuatro vocales y una letra sin clasificar.
texto = "Hola"
texto[0] = "h" # TypeError
Los strings son inmutables, por lo que se construye uno nuevo con la letra deseada más un slice del resto.
nombre = " carlos "
nombre.strip()
print(nombre) # " carlos "
La línea debe escribirse como nombre igual a nombre punto strip. Es el error más frecuente al trabajar con strings y no produce ningún mensaje de error.
texto = "Hola"
print(texto[4]) # IndexError
El último índice válido es tres. Para el último carácter conviene usar menos uno, que nunca se pasa.
respuesta = input("¿Continuar? (si/no): ")
if respuesta == "si":
print("Continuando...")
Si el usuario escribe Si o deja un espacio, la comparación falla en silencio. Se corrige aplicando strip y lower antes de comparar.
texto = "El gato"
if texto.find("perro"):
print("Encontrado") # se imprime
find devuelve menos uno, que Python considera verdadero. Se compara contra menos uno o se usa el operador in.
| Operación | Para qué sirve |
|---|---|
| len(texto) | Cuántos caracteres tiene |
| texto[i] | Obtener un carácter |
| texto[a:b] | Extraer una porción |
| for letra in texto | Recorrerlo carácter por carácter |
| parte in texto | Saber si contiene un texto |
| f"{variable}" | Insertar valores en un mensaje |
| Método | Devuelve |
|---|---|
| upper, lower, title | El texto con otro formato |
| strip | El texto sin espacios en los extremos |
| replace | El texto con una parte cambiada |
| find, count | Una posición o una cantidad |
| startswith, endswith, isdigit | Un booleano |
| split, join | Varias partes o un solo texto |
split entrega sus partes en una lista, la estructura que permite guardar muchos valores en una sola variable y el tema de la próxima clase.