5. Trabajar con texto usando cadenas
El texto está en todas partes en programación. Desde mostrar mensajes a las personas usuarias, hasta procesar archivos de datos o crear aplicaciones web, trabajar con texto es una de las habilidades más fundamentales que desarrollarás como programador o programadora. En Python, trabajamos con texto usando cadenas (strings) — secuencias de caracteres que pueden representar palabras, oraciones o cualquier tipo de dato textual.
Ya te has encontrado con cadenas brevemente en capítulos anteriores al usar print() e input(). Ahora exploraremos las cadenas en profundidad, aprendiendo cómo crearlas, manipularlas y usar las potentes capacidades integradas de cadenas de Python para resolver problemas reales de procesamiento de texto.
En este capítulo aprenderás a crear cadenas con caracteres especiales, combinar cadenas, extraer partes específicas de una cadena, cambiar su capitalización y formato, buscar texto dentro de cadenas y entender por qué las cadenas se comportan de forma diferente a los números cuando se trata de modificarlas. Al final, tendrás una base sólida para trabajar con texto en Python.
5.1) Literales de cadena y secuencias de escape
5.1.1) Crear literales de cadena
Un literal de cadena es un valor de cadena escrito directamente en tu código. Ya has visto cadenas creadas con comillas simples (') o comillas dobles ("):
# string_basics.py
greeting = 'Hello, World!'
message = "Python is great!"
print(greeting) # Output: Hello, World!
print(message) # Output: Python is great!Tanto las comillas simples como las dobles funcionan de forma idéntica en Python — la elección es tuya. Sin embargo, tener ambas opciones es útil cuando tu propia cadena contiene caracteres de comillas:
# quotes_in_strings.py
# Usar comillas dobles cuando la cadena contiene una comilla simple
sentence = "It's a beautiful day!"
print(sentence) # Output: It's a beautiful day!
# Usar comillas simples cuando la cadena contiene comillas dobles
quote = 'She said, "Hello!"'
print(quote) # Output: She said, "Hello!"Si necesitas incluir el mismo tipo de comilla que rodea tu cadena, puedes escaparla con una barra invertida (\):
# escaping_quotes.py
# Escapar una comilla simple dentro de una cadena con comillas simples
sentence = 'It\'s a beautiful day!'
print(sentence) # Output: It's a beautiful day!
# Escapar comillas dobles dentro de una cadena con comillas dobles
quote = "She said, \"Hello!\""
print(quote) # Output: She said, "Hello!"La barra invertida le dice a Python que la comilla que le sigue forma parte del contenido de la cadena, no el final de la cadena.
5.1.2) Cadenas multilínea con comillas triples
Para cadenas que abarcan múltiples líneas, Python ofrece comillas triples — ya sea tres comillas simples (''') o tres comillas dobles ("""):
# multiline_strings.py
poem = """Roses are red,
Violets are blue,
Python is awesome,
And so are you!"""
print(poem)
# Output:
# Roses are red,
# Violets are blue,
# Python is awesome,
# And so are you!Las cadenas con comillas triples preservan todos los saltos de línea y espacios exactamente como los escribes. Son especialmente útiles para bloques de texto largos, cadenas de documentación (que veremos en el Capítulo 19), o cuando necesitas incluir tanto comillas simples como dobles sin escaparlas:
# triple_quotes_convenience.py
dialogue = '''The teacher said, "Don't forget: it's important to practice!"'''
print(dialogue) # Output: The teacher said, "Don't forget: it's important to practice!"5.1.3) Secuencias de escape comunes
Más allá de escapar comillas, la barra invertida introduce secuencias de escape — combinaciones especiales de dos caracteres que representan caracteres que son difíciles o imposibles de teclear directamente:
# escape_sequences.py
# Newline: mueve a la siguiente línea
print("First line\nSecond line")
# Output:
# First line
# Second line
# Tab: inserta un espacio horizontal
print("Name:\tJohn\nAge:\t25")
# Output:
# Name: John
# Age: 25
# Backslash: para incluir una barra invertida literal
path = "C:\\Users\\Documents"
print(path) # Output: C:\Users\DocumentsAquí están las secuencias de escape más usadas:
| Escape Sequence | Meaning | Example Output |
|---|---|---|
\n | Nueva línea (salto de línea) | Dos líneas |
\t | Tabulación (espacio horizontal) | Texto indentado |
\\ | Barra invertida | carácter \ |
\' | Comilla simple | carácter ' |
\" | Comilla doble | carácter " |
Entender las secuencias de escape es crucial al trabajar con rutas de archivos (especialmente en Windows, que usa barras invertidas), salida formateada o cualquier texto que necesite formato especial.
5.1.4) Cadenas raw para barras invertidas literales
A veces quieres que las barras invertidas se traten literalmente, sin activar secuencias de escape. Esto es común cuando trabajas con rutas de archivos o expresiones regulares (que veremos brevemente en el Capítulo 39). Python ofrece cadenas raw (raw strings) anteponiendo la cadena con r:
# raw_strings.py
# Cadena normal: las barras invertidas activan secuencias de escape
regular = "C:\new\test"
print(regular) # Output: C:
# ew est
# (\n se convierte en nueva línea, \t se convierte en tab)
# Cadena raw: las barras invertidas son literales
raw = r"C:\new\test"
print(raw) # Output: C:\new\testEn una cadena raw, \n son literalmente los dos caracteres barra invertida y n, no una nueva línea. Las cadenas raw son especialmente útiles para rutas de archivos en Windows:
# windows_paths.py
# Sin cadena raw, necesitas escapar cada barra invertida
path1 = "C:\\Users\\John\\Documents\\file.txt"
# Con cadena raw, las barras invertidas funcionan de forma natural
path2 = r"C:\Users\John\Documents\file.txt"
print(path1) # Output: C:\Users\John\Documents\file.txt
print(path2) # Output: C:\Users\John\Documents\file.txtAmbos enfoques producen el mismo resultado, pero las cadenas raw son más legibles cuando tienes muchas barras invertidas.
5.2) Concatenación y repetición de cadenas
5.2.1) Concatenar cadenas con +
Puedes combinar cadenas usando el operador +, lo cual se llama concatenación:
# string_concatenation.py
first_name = "John"
last_name = "Smith"
# Combinando cadenas con +
full_name = first_name + " " + last_name
print(full_name) # Output: John Smith
# Construyendo cadenas más largas
greeting = "Hello, " + full_name + "!"
print(greeting) # Output: Hello, John Smith!La concatenación crea una nueva cadena poniendo las cadenas una detrás de la otra. Ten en cuenta que Python no añade espacios automáticamente — tienes que incluirlos explícitamente:
# concatenation_spacing.py
word1 = "Hello"
word2 = "World"
# Sin espacio
no_space = word1 + word2
print(no_space) # Output: HelloWorld
# Con espacio
with_space = word1 + " " + word2
print(with_space) # Output: Hello WorldPuedes concatenar tantas cadenas como quieras en una sola expresión:
# multiple_concatenation.py
address = "123" + " " + "Main" + " " + "Street"
print(address) # Output: 123 Main StreetLimitación importante: Solo puedes concatenar cadenas con otras cadenas. Intentar concatenar una cadena con un número causará un error:
# concatenation_error.py
age = 25
# Esto causará un error:
# message = "I am " + age + " years old" # TypeError!
# Debes convertir el número a cadena primero
message = "I am " + str(age) + " years old"
print(message) # Output: I am 25 years oldExploraremos la conversión entre cadenas y números con más detalle en la Sección 5.6.
5.2.2) Repetir cadenas con *
Python ofrece una forma cómoda de repetir una cadena varias veces usando el operador *:
# string_repetition.py
separator = "-" * 20
print(separator) # Output: --------------------
# Crear patrones
pattern = "abc" * 3
print(pattern) # Output: abcabcabc
# Útil para formatear la salida
print("=" * 30)
print("Important Message")
print("=" * 30)
# Output:
# ==============================
# Important Message
# ==============================El operador de repetición funciona con cualquier entero positivo:
# repetition_examples.py
# Repetir cero veces da una cadena vacía
nothing = "Hello" * 0
print(nothing) # Output: (empty string)
print(len(nothing)) # Output: 0
# Repetir una vez devuelve la cadena original
once = "Hello" * 1
print(once) # Output: Hello
# Repeticiones mayores
many = "Go! " * 5
print(many) # Output: Go! Go! Go! Go! Go!La repetición de cadenas es especialmente útil para crear separadores visuales, relleno o generar datos de prueba:
# practical_repetition.py
# Crear una caja de texto simple
width = 40
border = "=" * width
title = "Welcome"
padding = " " * ((width - len(title)) // 2)
print(border)
print(padding + title)
print(border)
# Output:
# ========================================
# Welcome
# ========================================5.2.3) Combinar concatenación y repetición
Puedes combinar ambos operadores en la misma expresión, siguiendo las reglas de precedencia de operadores de Python (multiplicación antes que suma, igual que con números):
# combined_operations.py
# La repetición ocurre primero, luego la concatenación
result = "=" * 10 + " Title " + "=" * 10
print(result) # Output: ========== Title ==========
# Usar paréntesis para controlar el orden
repeated_phrase = ("Hello " + "World ") * 3
print(repeated_phrase) # Output: Hello World Hello World Hello WorldEstas operaciones forman la base de la manipulación de cadenas, permitiéndote construir cadenas complejas a partir de piezas simples.
5.3) Indexación y slicing de cadenas
Las cadenas en Python son secuencias de caracteres, lo que significa que cada carácter tiene una posición específica. Puedes acceder a caracteres individuales o extraer partes de una cadena usando indexación y slicing.
5.3.1) Entender los índices de cadena
Cada carácter en una cadena tiene una posición numérica llamada índice. Python usa indexación basada en cero, lo que significa que el primer carácter está en el índice 0, el segundo en el índice 1, y así sucesivamente:
# string_indexing.py
text = "Python"
# Acceder a caracteres individuales por índice
print(text[0]) # Output: P (primer carácter)
print(text[1]) # Output: y (segundo carácter)
print(text[5]) # Output: n (sexto carácter)Aquí tienes una representación visual de cómo los índices se asignan a los caracteres:
String: P y t h o n
Index: 0 1 2 3 4 5Python también admite índices negativos, que cuentan desde el final de la cadena. El índice -1 se refiere al último carácter, -2 al penúltimo, y así sucesivamente:
# negative_indexing.py
text = "Python"
print(text[-1]) # Output: n (último carácter)
print(text[-2]) # Output: o (penúltimo)
print(text[-6]) # Output: P (primer carácter)Los índices negativos son especialmente útiles cuando quieres acceder a caracteres cerca del final de una cadena sin conocer su longitud exacta:
String: P y t h o n
Positive: 0 1 2 3 4 5
Negative: -6 -5 -4 -3 -2 -1Importante: Intentar acceder a un índice que no existe causará un IndexError:
# index_error.py
text = "Python"
# Esto funciona bien
print(text[5]) # Output: n
# Esto causa un error porque el índice 6 no existe
# print(text[6]) # IndexError: string index out of range5.3.2) Slicing de cadenas para extraer subcadenas
Mientras que la indexación te da un solo carácter, el slicing te permite extraer una parte de una cadena (llamada subcadena). La sintaxis básica es:
string[start:stop]Esto extrae caracteres desde el índice start hasta (pero sin incluir) el índice stop:
# basic_slicing.py
text = "Python Programming"
# Extraer caracteres desde el índice 0 hasta (sin incluir) el 6
print(text[0:6]) # Output: Python
# Extraer caracteres desde el índice 7 hasta 18
print(text[7:18]) # Output: Programming
# Extraer una parte intermedia
print(text[7:11]) # Output: ProgLo clave que debes recordar es que el índice stop no se incluye en el resultado. Piensa en los índices como puntos entre caracteres:
P y t h o n
0 1 2 3 4 5 6Así que text[0:6] significa "empieza en la posición 0 y detente antes de la posición 6", lo que te da los caracteres en las posiciones 0, 1, 2, 3, 4 y 5.
5.3.3) Omitir índices start o stop
Puedes omitir el índice start para hacer slicing desde el principio, u omitir el índice stop para hacer slicing hasta el final:
# omitting_indices.py
text = "Python Programming"
# Desde el inicio hasta el índice 6
print(text[:6]) # Output: Python
# Desde el índice 7 hasta el final
print(text[7:]) # Output: Programming
# Toda la cadena (desde el principio hasta el final)
print(text[:]) # Output: Python ProgrammingEstos atajos son muy comunes en código Python porque dejan claras las intenciones y evitan codificar longitudes a mano.
5.3.4) Usar índices negativos en slices
Los índices negativos también funcionan en slices, permitiéndote contar desde el final:
# negative_slice_indices.py
text = "Python Programming"
# Últimos 11 caracteres
print(text[-11:]) # Output: Programming
# Todo excepto los últimos 11 caracteres
print(text[:-11]) # Output: Python
# Últimos 7 caracteres
print(text[-7:]) # Output: ramming
# Desde el índice 7 hasta el antepenúltimo carácter
print(text[7:-3]) # Output: Programm (se detiene antes de 'ing')Los índices negativos son especialmente útiles cuando quieres excluir cierta cantidad de caracteres del final:
# removing_suffix.py
filename = "document.txt"
# Obtener todo excepto los últimos 4 caracteres (.txt)
name_without_extension = filename[:-4]
print(name_without_extension) # Output: document5.3.5) Hacer slicing con un valor de paso
Los slices pueden incluir un tercer valor llamado step (paso), que determina cuántos caracteres se saltan:
string[start:stop:step]# slicing_with_step.py
text = "Python Programming"
# Cada segundo carácter de toda la cadena
print(text[::2]) # Output: Pto rgamn
# Cada segundo carácter desde el índice 0 hasta el 6
print(text[0:6:2]) # Output: Pto
# Cada tercer carácter
print(text[::3]) # Output: Ph oaiUn truco especialmente útil es usar un paso de -1 para invertir una cadena:
# reversing_strings.py
text = "Python"
# Invertir toda la cadena
reversed_text = text[::-1]
print(reversed_text) # Output: nohtyP
# Ejemplo práctico: comprobar palíndromos
word = "radar"
if word == word[::-1]:
print(f"{word} is a palindrome!") # Output: radar is a palindrome!5.3.6) El slicing nunca causa errores
A diferencia de la indexación, el slicing es muy tolerante. Si especificas índices que están fuera de rango, Python simplemente los ajusta:
# safe_slicing.py
text = "Python"
# Todos estos funcionan sin errores
print(text[0:100]) # Output: Python (se detiene al final)
print(text[10:20]) # Output: (empty string - el inicio está más allá del final)
print(text[-100:3]) # Output: Pyt (el inicio se ajusta a 0)Este comportamiento hace que el slicing sea seguro incluso cuando no estás seguro de la longitud exacta de la cadena.
5.3.7) Ejemplos prácticos de slicing
Aquí hay algunos patrones comunes que usarás con frecuencia:
# practical_slicing.py
text = "Hello, World!"
# Primeros 5 caracteres
print(text[:5]) # Output: Hello
# Últimos 6 caracteres
print(text[-6:]) # Output: World!
# Todo excepto el primer y el último carácter
print(text[1:-1]) # Output: ello, World
# Cada dos caracteres
print(text[::2]) # Output: Hlo ol!
# Invertir la cadena
print(text[::-1]) # Output: !dlroW ,olleHEntender la indexación y el slicing es fundamental para el procesamiento de texto en Python. Estas técnicas aparecerán una y otra vez a lo largo de tu camino de programación.
5.4) Métodos comunes de cadenas para mayúsculas y espacios en blanco
Las cadenas de Python vienen con muchos métodos integrados — funciones que están asociadas a objetos de tipo cadena y realizan operaciones sobre ellos. En esta sección exploraremos métodos para cambiar la capitalización y gestionar espacios en blanco, que son esenciales para limpiar y formatear texto.
5.4.1) Entender los métodos de cadena
Un método se llama usando notación de punto: string.method_name(). Los métodos son funciones que pertenecen a un tipo específico de objeto. Para cadenas, Python proporciona docenas de métodos útiles:
# method_basics.py
text = "hello"
# Llamar a un método sobre una cadena
result = text.upper()
print(result) # Output: HELLO
# La cadena original no cambia (hablaremos de por qué en la Sección 5.8)
print(text) # Output: helloLos métodos se pueden encadenar porque cada método devuelve una nueva cadena:
# method_chaining.py
text = " hello world "
# Encadenar varios métodos
result = text.strip().upper().replace("WORLD", "PYTHON")
print(result) # Output: HELLO PYTHON5.4.2) Métodos de conversión de mayúsculas/minúsculas
Python ofrece varios métodos para cambiar la capitalización de las cadenas:
# case_methods.py
text = "Python Programming"
# Convertir a mayúsculas
print(text.upper()) # Output: PYTHON PROGRAMMING
# Convertir a minúsculas
print(text.lower()) # Output: python programming
# Poner en mayúscula la primera letra y el resto en minúsculas
print(text.capitalize()) # Output: Python programming
# Title case: pone en mayúscula la primera letra de cada palabra
print(text.title()) # Output: Python ProgrammingEstos métodos son especialmente útiles para estandarizar la entrada de usuario:
# case_normalization.py
# Simulando entrada de usuario
user_input = "YES"
# Comparación sin distinguir mayúsculas/minúsculas
if user_input.lower() == "yes":
print("User confirmed!") # Output: User confirmed!
# Otro enfoque usando upper()
command = "start"
if command.upper() == "START":
print("Starting process...") # Output: Starting process...El método title() pone en mayúscula la primera letra de cada palabra, lo que es útil para formatear nombres y títulos:
# title_case.py
name = "john smith"
print(name.title()) # Output: John Smith
book = "the great gatsby"
print(book.title()) # Output: The Great GatsbySin embargo, ten en cuenta que title() tiene limitaciones con apóstrofes y casos especiales:
# title_limitations.py
text = "it's a beautiful day"
print(text.title()) # Output: It'S A Beautiful Day (nota la S mayúscula)
# Para un "title case" más sofisticado, podrías necesitar lógica personalizadaEl método capitalize() solo pone en mayúscula el primer carácter de toda la cadena:
# capitalize_examples.py
sentence = "python is great"
print(sentence.capitalize()) # Output: Python is great
# Nota: solo se pone en mayúscula la primera letra
multi_word = "hello world"
print(multi_word.capitalize()) # Output: Hello world (no Hello World)5.4.3) Métodos para comprobar mayúsculas/minúsculas
Python también ofrece métodos para comprobar la capitalización de las cadenas:
# case_checking.py
text1 = "HELLO"
text2 = "hello"
text3 = "Hello World"
# Comprobar si todos los caracteres están en mayúsculas
print(text1.isupper()) # Output: True
print(text2.isupper()) # Output: False
# Comprobar si todos los caracteres están en minúsculas
print(text1.islower()) # Output: False
print(text2.islower()) # Output: True
# Comprobar si la cadena está en "title case"
print(text3.istitle()) # Output: True
print(text2.istitle()) # Output: FalseEstos métodos de comprobación devuelven True o False (valores booleanos que vimos en el Capítulo 3), lo que los hace perfectos para condiciones:
# case_checking_conditions.py
password = "SECRET123"
if password.isupper():
print("Password is all uppercase") # Output: Password is all uppercase5.4.4) Métodos para eliminar espacios en blanco
Espacios en blanco incluyen espacios, tabulaciones (\t) y saltos de línea (\n). Python ofrece métodos para eliminar espacios en blanco de los bordes de las cadenas:
# whitespace_removal.py
text = " Hello, World! "
# Eliminar espacios en blanco de ambos extremos
print(text.strip()) # Output: Hello, World!
# Eliminar espacios en blanco del lado izquierdo (inicio)
print(text.lstrip()) # Output: Hello, World!
# Eliminar espacios en blanco del lado derecho (final)
print(text.rstrip()) # Output: Hello, World!El método strip() es extremadamente útil para limpiar entradas de usuario:
# cleaning_input.py
# Simulando entrada de usuario con espacios extra
user_name = " John Smith "
# Limpiar la entrada
clean_name = user_name.strip()
print(f"Welcome, {clean_name}!") # Output: Welcome, John Smith!Estos métodos también eliminan tabulaciones y saltos de línea:
# strip_all_whitespace.py
text = "\n\t Hello \t\n"
print(repr(text)) # Output: '\n\t Hello \t\n'
cleaned = text.strip()
print(repr(cleaned)) # Output: 'Hello'Ten en cuenta que strip(), lstrip() y rstrip() solo eliminan espacios en blanco de los bordes, no del medio:
# strip_edges_only.py
text = " Hello World "
print(text.strip()) # Output: Hello World (los espacios del medio permanecen)5.4.5) Eliminar caracteres específicos
Los métodos strip también pueden eliminar caracteres específicos (no solo espacios en blanco) de los bordes:
# Remove multiple different characters
text = "...Hello!!!"
cleaned = text.strip(".!")
print(cleaned) # Output: HelloCuando pasas una cadena a strip(), elimina cualquier combinación de esos caracteres de los bordes:
# strip_character_set.py
text = "xxxyyyHelloyyyxxx"
# Eliminar cualquier 'x' o 'y' de ambos extremos
result = text.strip("xy")
print(result) # Output: Hello5.4.6) Ejemplos prácticos combinando métodos de mayúsculas y espacios en blanco
Aquí hay escenarios del mundo real donde estos métodos son invaluables:
# practical_text_cleaning.py
# Limpiar y estandarizar entrada de usuario
user_email = " JohnSmith@EXAMPLE.com "
clean_email = user_email.strip().lower()
print(clean_email) # Output: johnsmith@example.com
# Formatear nombres correctamente
raw_name = " john smith "
formatted_name = raw_name.strip().title()
print(formatted_name) # Output: John Smith
# Procesar comandos (sin distinguir mayúsculas/minúsculas)
command = " START "
if command.strip().upper() == "START":
print("Command recognized!") # Output: Command recognized!Estos métodos forman la base de la limpieza y normalización de texto, que usarás constantemente al procesar entradas de usuario, leer archivos o preparar datos para análisis.
5.5) Buscar y reemplazar en cadenas
Encontrar y modificar texto dentro de cadenas es una tarea común en programación. Python ofrece potentes métodos para buscar subcadenas y reemplazar texto.
5.5.1) Buscar subcadenas con find() e index()
El método find() busca una subcadena y devuelve el índice donde aparece por primera vez:
# find_method.py
text = "Python is great. Python is powerful."
# Encontrar la primera aparición de "Python"
position = text.find("Python")
print(position) # Output: 0 (se encuentra al principio)
# Encontrar "great"
position = text.find("great")
print(position) # Output: 10
# Buscar algo que no existe
position = text.find("Java")
print(position) # Output: -1 (no encontrado)El método find() devuelve -1 si la subcadena no se encuentra, lo que hace que sea seguro usarlo sin causar errores:
# safe_searching.py
text = "Hello, World!"
# Comprobar si existe una subcadena
if text.find("World") != -1:
print("Found 'World'!") # Output: Found 'World'!
if text.find("Python") == -1:
print("'Python' not found") # Output: 'Python' not foundTambién puedes buscar una subcadena empezando desde una posición específica:
# find_with_start.py
text = "Python is great. Python is powerful."
# Encontrar la primera aparición
first = text.find("Python")
print(first) # Output: 0
# Encontrar la siguiente aparición después de la primera
second = text.find("Python", first + 1)
print(second) # Output: 17El método index() funciona de forma similar a find(), pero lanza un error si la subcadena no se encuentra:
# index_method.py
text = "Hello, World!"
# Esto funciona bien
position = text.index("World")
print(position) # Output: 7
# Esto causaría un ValueError:
# position = text.index("Python") # ValueError: substring not foundCuándo usar cuál:
- Usa
find()cuando quieres comprobar si algo existe (devuelve -1 si no se encuentra). - Usa
index()cuando esperas que la subcadena esté allí (lanza error si no se encuentra).
# choosing_find_vs_index.py
text = "Python Programming"
# Usar find() para comprobaciones seguras
if text.find("Java") != -1:
print("Found Java")
else:
print("Java not found") # Output: Java not found
# Usar index() cuando estás seguro de que existe
position = text.index("Python") # Sabemos que Python está ahí
print(f"Found at position {position}") # Output: Found at position 05.5.2) Buscar desde el final con rfind() y rindex()
Los métodos rfind() y rindex() buscan desde la derecha (final) de la cadena:
# rfind_method.py
text = "Python is great. Python is powerful."
# Encontrar la última aparición de "Python"
last_position = text.rfind("Python")
print(last_position) # Output: 17
# Comparar con find() que da la primera aparición
first_position = text.find("Python")
print(first_position) # Output: 0Esto es útil cuando quieres la última aparición de algo:
# last_occurrence.py
filename = "document.backup.txt"
# Encontrar el último punto (para obtener la extensión)
last_dot = filename.rfind(".")
if last_dot != -1:
extension = filename[last_dot:]
print(extension) # Output: .txt5.5.3) Contar apariciones con count()
El método count() te dice cuántas veces aparece una subcadena:
# count_method.py
text = "Python is great. Python is powerful. Python is fun."
# Contar cuántas veces aparece "Python"
count = text.count("Python")
print(count) # Output: 3
# Contar un carácter
letter_count = text.count("o")
print(f"Letter 'o' appears {letter_count} times") # Output: Letter 'o' appears 4 timesTambién puedes contar dentro de un rango específico:
# count_in_range.py
text = "abcabcabc"
# Contar "abc" en toda la cadena
total = text.count("abc")
print(total) # Output: 3
# Contar "abc" solo en los primeros 6 caracteres
partial = text.count("abc", 0, 6)
print(partial) # Output: 25.5.4) Reemplazar texto con replace()
El método replace() crea una nueva cadena con todas las apariciones de una subcadena reemplazadas:
# replace_method.py
text = "I love Java. Java is great."
# Reemplazar todas las apariciones de "Java" por "Python"
new_text = text.replace("Java", "Python")
print(new_text) # Output: I love Python. Python is great.
# La cadena original no cambia
print(text) # Output: I love Java. Java is great.Puedes limitar el número de reemplazos con un tercer argumento:
# limited_replace.py
text = "one one one one"
# Reemplazar solo las primeras 2 apariciones
result = text.replace("one", "two", 2)
print(result) # Output: two two one oneEl método replace() distingue mayúsculas/minúsculas:
# case_sensitive_replace.py
text = "Python is great. python is powerful."
# Esto solo reemplaza "Python" (P mayúscula)
result = text.replace("Python", "Java")
print(result) # Output: Java is great. python is powerful.Para un reemplazo sin distinguir mayúsculas/minúsculas, necesitas manejarlo manualmente:
# case_insensitive_approach.py
text = "Python is great. python is powerful."
# Convertir a minúsculas, reemplazar, pero esto pierde la capitalización original
result = text.lower().replace("python", "java")
print(result) # Output: java is great. java is powerful.5.5.5) Ejemplos prácticos de búsqueda y reemplazo
Aquí hay escenarios del mundo real donde estos métodos brillan:
# practical_search_replace.py
# Limpiar datos: eliminar caracteres no deseados
phone = "123-456-7890"
clean_phone = phone.replace("-", "")
print(clean_phone) # Output: 1234567890
# Censurar palabras
message = "This is a bad word and another bad word."
censored = message.replace("bad", "***")
print(censored) # Output: This is a *** word and another *** word.
# Extraer extensión de archivo
filename = "document.txt"
dot_position = filename.rfind(".")
if dot_position != -1:
extension = filename[dot_position + 1:]
print(f"File type: {extension}") # Output: File type: txt
# Contar apariciones de una palabra (enfoque simple)
text = "Python is fun. I love Python. Python rocks!"
word = "Python"
occurrences = text.count(word)
print(f"'{word}' appears {occurrences} times") # Output: 'Python' appears 3 timesEstos métodos de búsqueda y reemplazo son herramientas fundamentales para procesamiento de texto, limpieza de datos y manipulación de cadenas en programas Python.
5.6) Convertir entre cadenas y números
Una de las tareas más comunes en programación es convertir entre representaciones textuales y numéricas. Cuando lees entrada de usuario con input(), obtienes una cadena — incluso si la persona escribe un número. De forma similar, cuando quieres mostrar números en texto, necesitas convertirlos a cadenas.
5.6.1) Convertir cadenas a números
Ya hemos visto las funciones int() y float() en el Capítulo 3, pero vamos a explorarlas más a fondo:
# string_to_number.py
# Convertir cadena a entero
age_text = "25"
age = int(age_text)
print(age) # Output: 25
print(type(age)) # Output: <class 'int'>
# Convertir cadena a flotante
price_text = "19.99"
price = float(price_text)
print(price) # Output: 19.99
print(type(price)) # Output: <class 'float'>Estas conversiones son esenciales al procesar entrada de usuario:
# user_input_conversion.py
# Simulando entrada de usuario (en código real, usarías input())
user_age = "30"
user_height = "5.9"
# Convertir a números para poder hacer operaciones
age = int(user_age)
height = float(user_height)
# Ahora podemos realizar cálculos
print(f"In 10 years, you'll be {age + 10}") # Output: In 10 years, you'll be 40
print(f"Your height in meters: {height * 0.3048:.2f}") # Output: Your height in meters: 1.80Importante: La cadena debe representar un número válido o tendrás un error:
# conversion_errors.py
# Estas conversiones funcionan bien
print(int("123")) # Output: 123
print(float("3.14")) # Output: 3.14
# Estas causan ValueError:
# print(int("hello")) # ValueError: invalid literal for int()
# print(int("12.5")) # ValueError: invalid literal for int() with base 10
# print(float("12.5.3")) # ValueError: could not convert string to floatAprenderemos a manejar estos errores de forma elegante en el Capítulo 28. Por ahora, ten presente que la conversión puede fallar si la cadena no representa un número válido.
5.6.2) Manejar espacios en blanco en cadenas numéricas
Las funciones de conversión de Python manejan automáticamente espacios en blanco al inicio y al final:
# whitespace_handling.py
# Todas estas conversiones funcionan a pesar de los espacios
print(int(" 42 ")) # Output: 42
print(float(" 3.14 ")) # Output: 3.14
# Combinar strip() con conversión por seguridad
user_input = " 100 "
number = int(user_input.strip())
print(number) # Output: 100Esto es útil al procesar entrada de usuario, que a menudo contiene espacios extra.
5.6.3) Convertir números a cadenas
La función str() convierte cualquier valor a su representación como cadena:
# number_to_string.py
age = 25
height = 5.9
# Convertir números a cadenas
age_text = str(age)
height_text = str(height)
print(type(age_text)) # Output: <class 'str'>
print(type(height_text)) # Output: <class 'str'>
# Ahora podemos concatenarlos con otras cadenas
message = "I am " + str(age) + " years old"
print(message) # Output: I am 25 years oldEsto es necesario siempre que quieras combinar números con cadenas:
# concatenation_with_numbers.py
score = 95
total = 100
# Debes convertir números a cadenas para concatenar
result = "Score: " + str(score) + "/" + str(total)
print(result) # Output: Score: 95/100
# Alternativa: usar f-strings (tratadas en detalle en el Capítulo 6)
result = f"Score: {score}/{total}"
print(result) # Output: Score: 95/1005.6.4) Convertir entre enteros y flotantes
También puedes convertir entre tipos entero y flotante:
# int_float_conversion.py
# Float a int (trunca la parte decimal)
price = 19.99
price_int = int(price)
print(price_int) # Output: 19 (se elimina la parte decimal, no se redondea)
# Int a float
age = 25
age_float = float(age)
print(age_float) # Output: 25.0Importante: Convertir de float a int trunca (corta) la parte decimal — no redondea:
# truncation_not_rounding.py
print(int(3.9)) # Output: 3 (¡no 4!)
print(int(3.1)) # Output: 3
print(int(-3.9)) # Output: -3 (trunca hacia cero)
# Para redondear, usa primero la función round() (vista en el Capítulo 4)
print(int(round(3.9))) # Output: 45.6.5) Ejemplos prácticos de conversión
Aquí hay escenarios del mundo real donde la conversión de tipos es esencial:
# practical_conversions.py
# Leer y procesar entrada de usuario
# (Simulando input() - en código real usarías input())
user_input = "42"
# Convertir a número para hacer cálculos
number = int(user_input)
doubled = number * 2
print(f"Double of {number} is {doubled}") # Output: Double of 42 is 84
# Construir salida formateada
name = "John"
age = 30
height = 5.9
# Método 1: convertir números a cadenas
info = name + " is " + str(age) + " years old and " + str(height) + " feet tall"
print(info) # Output: John is 30 years old and 5.9 feet tall
# Método 2: usar f-strings (más legible - visto en el Capítulo 6)
info = f"{name} is {age} years old and {height} feet tall"
print(info) # Output: John is 30 years old and 5.9 feet tall
# Procesar datos de archivos (vista previa)
data_line = "100,200,300" # Simulando una línea de un archivo CSV
numbers = data_line.split(",") # Dividir en una lista de cadenas
total = int(numbers[0]) + int(numbers[1]) + int(numbers[2])
print(f"Total: {total}") # Output: Total: 6005.6.6) Errores comunes de conversión
Ten en cuenta estos errores frecuentes:
# conversion_pitfalls.py
# Error 1: intentar convertir cadenas no numéricas
# text = "hello"
# number = int(text) # ValueError!
# Error 2: olvidar convertir antes de hacer operaciones aritméticas
age_text = "25"
# next_year = age_text + 1 # TypeError: can only concatenate str to str
# Enfoque correcto:
age = int(age_text)
next_year = age + 1
print(next_year) # Output: 26
# Error 3: perder precisión con int()
price = 19.99
price_int = int(price) # Se convierte en 19, ¡no 20!
print(price_int) # Output: 19
# Error 4: intentar convertir cadenas con comas o símbolos de moneda
# price_text = "$1,234.56"
# price = float(price_text) # ValueError!
# Necesitas limpiar la cadena primero:
price_text = "$1,234.56"
clean_price = price_text.replace("$", "").replace(",", "")
price = float(clean_price)
print(price) # Output: 1234.56Entender la conversión de tipos es crucial para crear programas que interactúan con personas y procesan datos del mundo real. Usarás estas conversiones constantemente a lo largo de tu camino con Python.
5.7) Comprobar subcadenas con in y not in
Python ofrece formas simples y legibles de comprobar si una cadena contiene otra usando los operadores in y not in. Son increíblemente útiles para validación, filtrado y toma de decisiones en tus programas.
5.7.1) Usar in para comprobar subcadenas
El operador in devuelve True si una cadena se encuentra dentro de otra, y False en caso contrario:
# in_operator.py
text = "Python is a powerful programming language"
# Comprobar si existe una subcadena
print("Python" in text) # Output: True
print("powerful" in text) # Output: True
print("Java" in text) # Output: FalseEsto es mucho más legible que usar find() o index():
# in_vs_find.py
text = "Hello, World!"
# Usando in (claro y legible)
if "World" in text:
print("Found World!") # Output: Found World!
# Usando find (menos legible)
if text.find("World") != -1:
print("Found World!") # Output: Found World!El operador in distingue mayúsculas/minúsculas:
# case_sensitivity.py
text = "Python Programming"
print("python" in text) # Output: False ('p' minúscula)
print("Python" in text) # Output: True ('P' mayúscula)
# Para comprobación sin distinguir mayúsculas/minúsculas, convierte a minúsculas primero
print("python" in text.lower()) # Output: True5.7.2) Usar not in para comprobar ausencia
El operador not in comprueba si una subcadena NO está presente:
# not_in_operator.py
text = "Python is great"
print("Java" not in text) # Output: True (Java no está)
print("Python" not in text) # Output: False (Python sí está)Esto es particularmente útil para validación:
# validation_examples.py
# Comprobar caracteres no válidos en un nombre de usuario
username = "john_smith"
if " " not in username:
print("Username is valid (no spaces)") # Output: Username is valid (no spaces)5.7.3) Métodos adicionales de comprobación de cadenas
Python ofrece varios otros métodos útiles para comprobar propiedades de cadenas:
# string_checking_methods.py
text = "Python"
# Comprobar si la cadena empieza con una subcadena
print(text.startswith("Py")) # Output: True
print(text.startswith("Ja")) # Output: False
# Comprobar si la cadena termina con una subcadena
print(text.endswith("on")) # Output: True
print(text.endswith("ing")) # Output: False
# Estos son más precisos que usar in
filename = "report.txt"
print(filename.endswith(".txt")) # Output: True
print(".txt" in filename) # Output: True (pero menos preciso)
# startswith/endswith pueden comprobar múltiples opciones
filename = "document.pdf"
print(filename.endswith((".pdf", ".doc", ".txt"))) # Output: TrueEstos métodos de comprobación son herramientas esenciales para validación de entrada, filtrado de datos y lógica condicional en tus programas. Hacen tu código más legible y mantenible en comparación con búsquedas manuales de cadenas.
5.8) Las cadenas son inmutables: lo que eso significa en la práctica
Una de las características más importantes de las cadenas en Python es que son inmutables — una vez creadas, no se pueden cambiar. Esto puede parecer una limitación al principio, pero entender la inmutabilidad es crucial para escribir código correcto en Python y evitar errores sutiles.
5.8.1) Qué significa inmutabilidad
Cuando decimos que las cadenas son inmutables, queremos decir que no puedes modificar los caracteres de una cadena existente. Cualquier operación que parezca "cambiar" una cadena en realidad crea una nueva cadena:
# immutability_basics.py
text = "Hello"
# Esto parece que cambia la cadena, pero no lo hace
text = text + " World"
print(text) # Output: Hello World
# Lo que realmente ocurrió:
# 1. Python creó una nueva cadena "Hello World"
# 2. La variable 'text' ahora se refiere a esta nueva cadena
# 3. La cadena original "Hello" sigue existiendo (hasta que el recolector de basura la elimine)No puedes cambiar caracteres individuales de una cadena:
# cannot_modify_characters.py
text = "Hello"
# Esto causa un error:
# text[0] = "J" # TypeError: 'str' object does not support item assignment
# Debes crear una nueva cadena en su lugar
text = "J" + text[1:]
print(text) # Output: JelloEsto es fundamentalmente diferente de cómo funcionan las listas (que veremos en el Capítulo 13). Las listas son mutables — puedes cambiar sus elementos:
# lists_are_mutable.py
# Vista previa de listas (tratadas en el Capítulo 13)
numbers = [1, 2, 3]
numbers[0] = 10 # Esto funciona bien con listas
print(numbers) # Output: [10, 2, 3]
# Pero las cadenas no permiten esto:
text = "Hello"
# text[0] = "J" # ¡TypeError con cadenas!5.8.2) Por qué los métodos de cadena devuelven nuevas cadenas
Todos los métodos de cadena que parecen modificarla en realidad devuelven una nueva cadena, dejando la original sin cambios:
# methods_return_new_strings.py
original = "hello world"
# Estos métodos devuelven nuevas cadenas
uppercase = original.upper()
capitalized = original.capitalize()
replaced = original.replace("world", "Python")
# La cadena original no cambia
print(original) # Output: hello world
print(uppercase) # Output: HELLO WORLD
print(capitalized) # Output: Hello world
print(replaced) # Output: hello PythonPor esto necesitas asignar el resultado a una variable (o usar la misma variable) para conservar los cambios:
# keeping_changes.py
text = " hello "
# Incorrecto: se pierde el resultado
text.strip()
print(text) # Output: hello (¡todavía tiene espacios!)
# Correcto: asignar el resultado
text = text.strip()
print(text) # Output: hello (espacios eliminados)Este es un error común para principiantes:
# common_mistake.py
message = "python programming"
# Error: llamar a métodos pero no usar el resultado
message.upper()
message.replace("python", "Python")
print(message) # Output: python programming (¡sin cambios!)
# Correcto: asignar resultados
message = message.upper()
message = message.replace("PYTHON", "Python")
print(message) # Output: Python PROGRAMMING5.8.3) Implicaciones de la inmutabilidad
Entender la inmutabilidad te ayuda a escribir mejor código:
1. Las cadenas son seguras de compartir:
# safe_sharing.py
original = "Hello"
copy = original # Ambas variables apuntan a la misma cadena
# Como las cadenas son inmutables, esto es seguro
copy = copy + " World"
print(original) # Output: Hello (sin cambios)
print(copy) # Output: Hello World (nueva cadena)2. Las operaciones con cadenas crean nuevos objetos:
# new_objects.py
text = "Python"
# Cada operación crea un nuevo objeto cadena
result1 = text.upper()
result2 = text.lower()
result3 = text.replace("P", "J")
# Todos son objetos diferentes
print(id(text)) # Alguna dirección de memoria
print(id(result1)) # Dirección de memoria diferente
print(id(result2)) # Dirección de memoria diferente
print(id(result3)) # Dirección de memoria diferente3. Construir cadenas en bucles puede ser ineficiente:
# inefficient_string_building.py
# Esto crea muchos objetos cadena temporales
result = ""
for i in range(5):
result = result + str(i) # Crea una nueva cadena cada vez
print(result) # Output: 01234
# Enfoque más eficiente (para muchas concatenaciones):
# Usar una lista y join (veremos esto en el Capítulo 6)
parts = []
for i in range(5):
parts.append(str(i))
result = "".join(parts)
print(result) # Output: 012345.8.4) Inmutabilidad y argumentos de función
Cuando pasas una cadena a una función, no necesitas preocuparte de que se modifique accidentalmente:
# safe_function_arguments.py
def process_text(text):
# Cualquier operación crea nuevas cadenas
text = text.upper()
text = text.replace("A", "X")
return text
original = "banana"
result = process_text(original)
print(original) # Output: banana (sin cambios)
print(result) # Output: BXNXNX (versión modificada)Esto es diferente de los tipos mutables (como listas, que veremos en el Capítulo 13), donde las modificaciones dentro de las funciones afectan al objeto original.
5.8.5) Visualizar la inmutabilidad
Aquí tienes una representación visual de lo que ocurre cuando "modificas" una cadena:
Entender que las cadenas son inmutables te ayuda a:
- Evitar errores donde olvidas capturar los resultados de métodos.
- Entender por qué las operaciones con cadenas crean nuevos objetos.
- Escribir código más eficiente al construir cadenas grandes.
- Compartir cadenas de forma segura entre diferentes partes de tu programa.
Esta inmutabilidad es una característica fundamental que distingue a las cadenas de tipos mutables como las listas, que exploraremos en detalle en la Parte IV de este libro.
Resumen del capítulo:
En este capítulo has aprendido los fundamentos de trabajar con texto en Python usando cadenas. Ahora sabes cómo:
- Crear literales de cadena usando comillas y secuencias de escape
- Combinar cadenas con concatenación y repetición
- Acceder a caracteres individuales y extraer subcadenas con indexación y slicing
- Transformar cadenas usando métodos para conversión de mayúsculas/minúsculas y eliminación de espacios en blanco
- Buscar y reemplazar texto dentro de cadenas
- Convertir entre cadenas y números para procesar entradas y formatear salidas
- Comprobar subcadenas usando los operadores
inynot in - Reconocer que las cadenas son inmutables y qué significa eso para tu código
Estas habilidades de manipulación de cadenas forman la base del procesamiento de texto en Python. Usarás estas técnicas constantemente al crear interfaces de usuario, procesar archivos de datos, validar entradas y formatear salidas.
En el próximo capítulo, ampliaremos estos fundamentos explorando técnicas más avanzadas de manejo de cadenas, incluyendo dividir y unir cadenas, formateo potente con f-strings y el método format(), y entender la codificación de texto para trabajar con caracteres internacionales.