Skip to content
This page has been auto-translated and may contain errors.View in English

Cadenas

El texto aparece en casi todos los programas que escribes. Nombres, mensajes, puntajes, etiquetas. En Python, cualquier fragmento de texto se llama cadena (string): cualquier valor que envuelvas entre comillas. Simples o dobles, ambas funcionan igual.

Las cadenas son el tipo de texto principal de Python. Contienen todo, desde un nombre de usuario hasta una ruta de URL o una salida formateada. Las comillas simples y dobles producen resultados idénticos; la elección es estilística.

str es el tipo de secuencia Unicode inmutable de Python. Se ubica en cada frontera del sistema: E/S de terminal, contenido de archivos, respuestas de red, datos serializados. Ambos estilos de comillas producen el mismo objeto; el tokenizador los trata de manera idéntica.

python
greeting = "Hola, mundo"
username = 'sofia'

La única vez que importa la elección de las comillas es cuando tu texto contiene comillas. Usa el estilo opuesto para no tener que escaparlas:

La convención de la comunidad son las comillas dobles. La razón práctica para cambiar de estilo es evitar el escape cuando el contenido contiene ese carácter:

La convención son las comillas dobles. La única razón para cambiar es evitar un escape con barra invertida cuando el contenido contiene ese delimitador:

python
note    = "It's a great day"      # apóstrofo dentro, usa comillas dobles
message = 'She said "hello"'      # comillas dobles dentro, usa comillas simples
escaped = "She said \"hello\""    # o escapa con una barra invertida

Inmutabilidad

Las cadenas son inmutables: una vez que creas una, no puedes modificarla. Piensa en una cadena como algo permanentemente fijo desde el momento en que se crea. Cualquier operación que parezca modificar una cadena en realidad produce una completamente nueva. La original permanece exactamente como estaba.

Las cadenas son inmutables: ningún método modifica una cadena en su lugar. Cada operación que transforma texto devuelve una nueva cadena y deja la original intacta. La consecuencia práctica es que una llamada a un método que no asignes a nada no tiene efecto sobre nada.

Los objetos str son inmutables: el búfer interno se fija en la construcción y no se puede escribir en él. Esto les da a las cadenas tres propiedades útiles: son hashables (válidas como claves de diccionario y miembros de conjuntos), seguras para compartir entre referencias sin copiar y elegibles para la optimización de internación de CPython en literales cortos.

python
name = "sofia"
name = name.upper()   # "SOFIA" es una nueva cadena; "sofia" no cambia

La consecuencia directa: no puedes cambiar un carácter en una posición específica. Python generará un error si lo intentas.

python
name = "sofia"
name[0] = "S"   # TypeError: 'str' object does not support item assignment

Para obtener una cadena modificada, construye una nueva usando segmentación o un método. Ambos se cubren a continuación.

Intentar la asignación de caracteres muestra la restricción directamente:

python
name = "sofia"
name[0] = "S"   # TypeError: 'str' object does not support item assignment

Cuando necesitas una versión modificada, las herramientas estándar son la segmentación con concatenación para ediciones posicionales, y replace() para sustituciones. Ambas producen una nueva cadena y dejan la original intacta.

str.__setitem__ no está implementado; la asignación de elementos genera TypeError incondicionalmente. Para modificación posicional, usa segmentación: name[:1].upper() + name[1:]. Para sustitución, replace(). Para ensamblar muchas piezas, "".join(parts) es importante: el s += chunk repetido dentro de un bucle es O(n²) porque cada + asigna un nuevo búfer de la longitud combinada y copia ambos operandos. join() asigna una sola vez.

Indexación y segmentación

Cada carácter de una cadena tiene una posición numerada, comenzando desde cero. Puedes leer caracteres individuales colocando ese número de posición entre corchetes. Los números negativos cuentan hacia atrás desde el final.

Las cadenas son secuencias con indexación basada en cero. Los índices negativos cuentan desde el final. La segmentación extrae cualquier rango contiguo en una sola expresión, y nunca genera un error con valores fuera de rango.

str implementa el protocolo de secuencia completo. El acceso por subíndice (s[i]) pasa por __getitem__ con un entero y genera IndexError si el valor está fuera de rango. La segmentación (s[start:stop:step]) pasa un objeto slice; los índices se ajustan silenciosamente al rango válido, por lo que no es posible generar IndexError desde una segmentación.

python
word = "Python"
#       012345

print(word[0])    # "P"
print(word[2])    # "t"
print(word[5])    # "n"
print(word[-1])   # "n"  (último carácter)
print(word[-2])   # "o"  (penúltimo)

-1 siempre es el último carácter, -2 el penúltimo, y así sucesivamente. Son útiles cuando quieres el final de una cadena sin conocer su longitud exacta.

Los índices negativos se envuelven: -1 es len(s) - 1, -2 es len(s) - 2. Más útiles para acceso anclado al final cuando no quieres calcular manualmente la longitud. Un índice negativo que se sale del rango aún genera IndexError, igual que uno positivo.

Los índices negativos se normalizan a len(s) + i antes de la verificación de límites. No hay un tratamiento especial en el intérprete; es aritmética. Fuera de rango genera IndexError independientemente del signo.

La segmentación extrae un fragmento. [start:stop] incluye start y excluye stop:

python
word = "Python"

print(word[0:2])   # "Py"     (posiciones 0 y 1)
print(word[2:])    # "thon"   (posición 2 al final)
print(word[:3])    # "Pyt"    (inicio a la posición 2)
print(word[:])     # "Python" (una copia de la cadena completa)
print(word[::2])   # "Pto"    (cada segundo carácter)
print(word[::-1])  # "nohtyP" (invertida)

Tres patrones que usarás más: word[:n] para los primeros n caracteres, word[n:] para todo desde la posición n en adelante, word[-n:] para los últimos n caracteres. word[::-1] invierte una cadena. Se ve extraño la primera vez, pero es idiomático en Python y lo verás a menudo.

A diferencia de la indexación directa, la segmentación nunca genera IndexError. Python ajusta silenciosamente los índices fuera de rango, por lo que word[100:] en una cadena corta devuelve "" en lugar de fallar. El argumento de paso controla el salto: word[::2] toma cada otro carácter, word[::-1] recorre al revés.

s[start:stop:step] pasa slice(start, stop, step) a __getitem__. Los tres argumentos tienen como valor predeterminado None, no 0 y len(). Con un paso negativo, los valores predeterminados se invierten: start toma len - 1 por defecto, stop toma -(len + 1). Eso es lo que hace que [::-1] recorra la cadena completa al revés sin límites explícitos.

Métodos esenciales de cadenas

Las cadenas vienen con un conjunto de métodos integrados: operaciones que llamas directamente sobre cualquier valor de cadena. Escribes la cadena (o la variable que la contiene), luego un punto, luego el nombre del método. Cada método devuelve una nueva cadena. La original nunca se modifica.

Los métodos de cadena son funciones asociadas al tipo str. Como las cadenas son inmutables, cada método devuelve una nueva cadena en lugar de modificar la original. Una llamada a un método que no asignas ni pasas a algún lugar no tiene efecto duradero.

Los métodos de str se definen en el objeto de tipo y se implementan en C. Todos los métodos transformadores siguen el contrato de inmutabilidad: devuelven nuevos objetos str. La implementación de CPython es consciente de Unicode en todo momento; los métodos operan sobre puntos de código, no sobre bytes.

Capitalización

python
text = "Hello, World"

text.lower()       # "hello, world"
text.upper()       # "HELLO, WORLD"
text.title()       # "Hello, World"  (cada palabra capitalizada)
text.capitalize()  # "Hello, world"  (solo la primera palabra)

lower() y upper() son los dos que más usarás. lower() es particularmente útil al comparar texto: "Sofia" y "sofia" se convierten en lo mismo una vez que llamas a .lower() en ambos lados.

lower() es el paso de normalización estándar antes de la comparación o el almacenamiento. title() capitaliza la primera letra de cada palabra usando una regla simple que falla con contracciones: "it's" se convierte en "It'S". Trátalo como formato solo de visualización.

lower() aplica la conversión completa de mayúsculas y minúsculas Unicode. Para comparación insensible a mayúsculas y minúsculas, casefold() es más correcto: aplica transformaciones adicionales (por ejemplo, la ß alemana se convierte en ss) que lower() omite. title() capitaliza después de cualquier carácter no alfanumérico, lo que maneja mal las contracciones y los nombres con guiones. Para una capitalización de título correcta, implementa la lógica manualmente.

Espacios en blanco

python
text = "  hello  "

text.strip()    # "hello"    (ambos lados)
text.lstrip()   # "hello  "  (solo izquierda)
text.rstrip()   # "  hello"  (solo derecha)

strip() elimina los espacios de ambos extremos de una cadena. Lo usarás casi siempre que manejes entradas de usuario o texto de un archivo, porque los espacios extraviados causan fallas silenciosas: "sofia" != "sofia ".

strip() elimina todos los espacios en blanco iniciales y finales: espacios, tabulaciones y saltos de línea. Las variantes direccionales te permiten limpiar solo un lado, útil para eliminar un salto de línea final sin tocar la indentación. Las tres aceptan un argumento opcional de caracteres para eliminar caracteres específicos en su lugar.

strip() sin argumentos elimina los caracteres para los cuales str.isspace() devuelve True, un conjunto consciente de Unicode que incluye espacios en blanco no ASCII. Con un argumento de carácter, elimina cualquier carácter en ese conjunto de ambos extremos (una verificación de pertenencia a caracteres, no una coincidencia de prefijo). "xxhelloxx".strip("x") devuelve "hello". Los argumentos de varios caracteres eliminan cualquiera de esos caracteres individualmente, lo que es una fuente común de errores sutiles.

Búsqueda

python
text = "Hello, world"

text.find("world")         # 7
text.find("Python")        # -1  (no encontrado)
text.count("l")            # 3
text.startswith("Hello")   # True
text.endswith("world")     # True

find() devuelve la posición donde comienza un fragmento de texto dentro de tu cadena. Si no está, devuelve -1. Usa startswith() y endswith() cuando solo te importa si la cadena comienza o termina con algo específico.

find() devuelve el índice de inicio de la primera coincidencia, o -1. La convención -1 te permite usar el resultado directamente en segmentación o aritmética sin una verificación. startswith() y endswith() aceptan cada uno una tupla de cadenas, lo que facilita probar múltiples prefijos o sufijos en una sola llamada.

find() es un escaneo lineal de izquierda a derecha, O(n*m) en el peor caso. index() es idéntico pero genera ValueError si no hay coincidencia: usa index() cuando la ausencia es un error de programación, find() cuando es entrada esperada. startswith() y endswith() cortocircuitan en la primera no coincidencia y son más rápidos que una verificación con find() o in para pruebas de prefijo/sufijo.

Reemplazo

python
text = "Hello, world"

text.replace("world", "Python")   # "Hello, Python"
text.replace("l", "L")            # "HeLLo, worLd"  (todas las ocurrencias)
text.replace("l", "L", 1)         # "HeLlo, world"  (solo la primera)

replace() cambia cada ocurrencia de un fragmento de texto por otro y te devuelve una nueva cadena. La original no se modifica. Pasa un tercer argumento si solo quieres reemplazar la primera ocurrencia.

replace() reemplaza todas las ocurrencias no superpuestas por defecto. El argumento de conteo limita cuántas se reemplazan. Como devuelve una nueva cadena, las llamadas pueden encadenarse: text.replace("a", "A").replace("e", "E") aplica ambas sustituciones en secuencia.

replace() realiza un escaneo literal de subcadenas y construye el resultado en una sola asignación cuando no se proporciona un conteo; con un conteo se detiene antes. Para sustitución basada en patrones, el módulo re de Python es la herramienta adecuada. Eso se cubre en el capítulo de Módulos.

División y unión

split() corta una cadena en piezas en un separador y las devuelve como una lista. Le dices con qué cortar:

split() divide en un separador y devuelve los segmentos como una lista. Llamado sin argumento, divide en cualquier secuencia de espacios en blanco y descarta las cadenas vacías de espacios consecutivos múltiples:

split(sep) escanea de izquierda a derecha, dividiendo en cada ocurrencia no superpuesta de sep. Sin argumento usa un algoritmo diferente: divide en cualquier secuencia de espacios en blanco y elimina los espacios en blanco iniciales y finales del resultado. rsplit(sep, n) divide desde la derecha, útil para aislar el último segmento de una ruta con puntos o un identificador con espacios de nombres:

python
csv_row = "Sofía,28,Ciudad de México"
parts = csv_row.split(",")     # ["Sofía", "28", "Ciudad de México"]

"  hello   world  ".split()   # ["hello", "world"]

¿Qué es una lista?

Una lista es una colección ordenada de valores. ["Sofía", "28", "Ciudad de México"] arriba es una. Las listas tienen su propio capítulo; por ahora, trátalas como una secuencia de elementos que split() produce y join() consume.

join() hace lo contrario: combina una lista de cadenas en una sola. La cadena antes de .join() se coloca entre cada elemento:

python
words = ["Hola", "mundo"]

" ".join(words)    # "Hola mundo"
", ".join(words)   # "Hola, mundo"
"".join(words)     # "Holamundo"

El patrón que debes recordar: separador.join(lista_de_cadenas). El separador va a la izquierda, la lista a la derecha. " ".join(words) pone un espacio entre cada palabra. "".join(words) las pega sin nada entre ellas.

join() es la herramienta adecuada cuando estás ensamblando una sola cadena a partir de múltiples piezas. Realiza una sola asignación en lugar de crear una nueva cadena en cada paso. Para dos o tres cadenas, + está perfectamente bien. Una vez que tienes una lista de tamaño significativo, recurre a join().

join() es O(n): llama a __iter__ una vez, calcula la longitud total necesaria en una sola pasada, realiza una sola asignación y luego escribe cada pieza y el separador directamente en el búfer. El + repetido es O(n²): cada operación asigna un nuevo búfer de la longitud combinada y copia ambos operandos. CPython tiene una optimización limitada para += repetido en una sola variable local, pero es frágil ante refactorizaciones y no está garantizada. join() siempre es correcto y siempre es rápido.

f-strings

Los f-strings incrustan valores directamente dentro del texto. Pon f antes de la comilla de apertura, luego envuelve cualquier variable o expresión entre llaves. Python lo completa cuando se ejecuta el código. También puedes agregar dos puntos después del valor para controlar cómo se muestra.

Los f-strings evalúan cualquier expresión dentro de {} en tiempo de ejecución y convierten el resultado a una cadena. Dos puntos dentro de las llaves introducen una especificación de formato: una sintaxis compacta para controlar lugares decimales, alineación y formato de números.

Los f-strings (PEP 498) compilan cada expresión {} a bytecode que llama a format(value, spec), que delega a value.__format__(spec). Cualquier clase que implemente __format__ controla su propia visualización dentro de un f-string. Las banderas de conversión !r, !s, !a aplican repr(), str() o ascii() antes de la llamada de formato.

python
name  = "Sofía"
score = 94.5

print(f"¡Hola, {name}!")           # "¡Hola, Sofía!"
print(f"Puntaje: {score:.1f}%")    # "Puntaje: 94.5%"
print(f"2 + 2 = {2 + 2}")          # "2 + 2 = 4"
print(f"Nombre: {name.upper()}")   # "Nombre: SOFÍA"

La especificación de formato después de : controla cómo se muestra el valor:

SpecSignificadoEjemplo
.2f2 lugares decimalesf"{3.14159:.2f}""3.14"
.0%porcentaje, sin decimalesf"{0.94:.0%}""94%"
,separador de milesf"{1000000:,}""1,000,000"
>10alinear a la derecha en 10 caracteresf"{'hi':>10}"" hi"

Usarás .2f más: cada vez que muestres un decimal y quieras un número ordenado en lugar de una larga serie de dígitos. Todo lo demás en la tabla está ahí cuando lo necesites. Puedes poner cualquier variable, aritmética o llamada a método dentro de {}.

.2f y .0% cubren la mayoría del formato de visualización. Los especificadores de alineación (>, <, ^) producen salida tabular cuando se combinan con un ancho. El patrón general es {value:[align][width][.precision][type]}. Una vez que reconoces las piezas, cualquier especificación es legible sin memorizar todas las combinaciones.

La especificación se pasa textualmente a __format__; los tipos integrados la manejan en C. !r es la bandera de conversión más útil: llama a repr() antes de formatear, lo que agrega comillas alrededor de las cadenas y hace visibles los caracteres invisibles (tabulaciones, espacios finales, saltos de línea) como secuencias de escape. Las clases personalizadas pueden implementar __format__ para aceptar cadenas de especificación arbitrarias y producir cualquier salida.

Cadenas multilínea

Para escribir una cadena que abarque más de una línea, usa comillas triples: tres " al inicio y tres al final. Python preserva todos los saltos de línea y el espaciado exactamente como los escribiste.

Las cadenas con comillas triples preservan todo el espacio en blanco y los saltos de línea literalmente. Son estándar para bloques de texto largos como plantillas de correo electrónico y consultas SQL, y para docstrings: la documentación en línea colocada al inicio del cuerpo de una función o clase.

Los literales con comillas triples preservan todos los caracteres textualmente, incluido el espacio en blanco inicial de cada línea. Cuando se usan como la primera declaración en el cuerpo de una función, clase o módulo, Python almacena la cadena como el atributo __doc__ de ese objeto. Herramientas como help() la muestran; el espacio en blanco inicial generalmente se elimina con textwrap.dedent(). Los triples ''' y """ son equivalentes; """ es la convención.

python
message = """
Estimada Sofía,

Gracias por su pedido.

Saludos cordiales,
El Equipo
"""

Secuencias de escape

Algunos caracteres son difíciles de escribir directamente dentro de una cadena. Python usa secuencias de escape: una barra invertida seguida de una letra que representa algo. Las dos que usarás constantemente son \n para una nueva línea y \t para una tabulación.

Las secuencias de escape te permiten incrustar caracteres que de otra manera romperían la sintaxis o no se pueden escribir directamente. Las que usarás: \n (nueva línea), \t (tabulación), \\ (una barra invertida literal), \" y \' (comillas dentro de una cadena con delimitador coincidente). Las rutas de Windows requieren barras invertidas, que chocan con el procesamiento de escape. Antepón r para desactivarlo.

Python admite el conjunto de escapes al estilo C más escapes Unicode: \uXXXX (punto de código de 16 bits), \UXXXXXXXX (32 bits), \xNN (valor de byte hexadecimal), \N{name} (carácter Unicode con nombre). Los literales de cadena en bruto (r"...") suprimen todo el procesamiento de escape, pasando cada barra invertida textualmente a la cadena. Esto es esencial para rutas de Windows y expresiones regulares, donde las barras invertidas tienen significado para el consumidor en lugar del tokenizador de Python.

SecuenciaCarácter
\nNueva línea
\tTabulación
\\Barra invertida literal
\"Comilla doble
\'Comilla simple
python
print("Línea uno\nLínea dos")      # dos líneas de salida
print("Nombre:\tSofía")            # Nombre:   Sofía
path = r"C:\Users\Sofia\Documents" # cadena en bruto, sin procesamiento de escape

Verificar el contenido de cadenas

Python tiene métodos que responden preguntas de sí/no sobre lo que contiene una cadena. Devuelven True o False. El más útil al principio: isdigit() te permite verificar si una cadena es toda números antes de convertirla, para que puedas evitar un fallo en entradas inesperadas.

Los métodos is* prueban cada uno una propiedad específica de toda la cadena y devuelven True solo si cada carácter satisface la condición. Su uso principal es la validación de entrada: verificar antes de convertir para evitar un fallo en entradas inesperadas. isdigit() antes de int() es el patrón clásico.

Los métodos is* usan verificaciones de categoría Unicode, no rangos ASCII. isdigit() devuelve True para dígitos en superíndice y otros puntos de código Unicode numéricos más allá de 0-9. Para verificación estricta de dígitos ASCII, combina s.isascii() and s.isdigit(). isnumeric() es aún más amplio, cubriendo fracciones y caracteres Unicode con valor numérico. Sabe cuál realmente necesitas antes de usarlo.

python
"42".isdigit()       # True
"hello".isalpha()    # True
"hello42".isalnum()  # True
"   ".isspace()      # True
"Hello".islower()    # False
"HELLO".isupper()    # True

En la práctica

Elimina los espacios en blanco, normaliza la capitalización, luego extrae lo que necesitas. Esta secuencia maneja casi cualquier texto proporcionado por el usuario:

python
raw_input = "  [email protected]  "
email     = raw_input.strip().lower()   # "[email protected]"

at_pos   = email.find("@")
username = email[:at_pos]
domain   = email[at_pos + 1:]

print(f"Usuario: {username}")   # "sofia"
print(f"Dominio: {domain}")     # "example.com"

Construir una URL a partir de partes e inmediatamente validarla y analizarla:

python
BASE_URL = "https://api.example.com"
version  = "v2"
resource = "users"
user_id  = 42

url      = f"{BASE_URL}/{version}/{resource}/{user_id}"
# "https://api.example.com/v2/users/42"

protocol = url.split("://")[0]                    # "https"
secured  = url.startswith("https")
domain   = url.split("://")[1].split("/")[0]      # "api.example.com"

print(f"Protocolo: {protocol}")
print(f"Seguro   : {secured}")
print(f"Dominio  : {domain}")

Analizar una línea de registro estructurada usando find(), segmentación y alineación de f-strings:

python
log_entry = "[2024-01-15 09:42:11] ERROR: File not found: report.csv"

timestamp = log_entry[1:20]
rest      = log_entry[22:]                # "ERROR: File not found: report.csv"
colon_pos = rest.find(":")
level     = rest[:colon_pos]              # "ERROR"
message   = rest[colon_pos + 2:]          # "File not found: report.csv"

print(f"[{timestamp}] {level:>8}: {message}")
# [2024-01-15 09:42:11]    ERROR: File not found: report.csv

find() localiza el límite, la segmentación extrae las partes y la especificación de formato >8 alinea a la derecha la etiqueta de severidad para que las columnas se mantengan consistentes cuando los nombres de nivel difieren en longitud.

Referencia de métodos

MétodoQué hace
.lower() / .upper()Convierte todo a minúsculas / todo a mayúsculas
.title() / .capitalize()Capitaliza cada palabra / solo la primera
.strip() / .lstrip() / .rstrip()Elimina espacios en blanco circundantes
.find(sub)Índice de la primera coincidencia, o -1
.count(sub)Cuántas veces aparece sub
.startswith(s) / .endswith(s)Verificación de prefijo / sufijo
.replace(old, new)Reemplaza ocurrencias
.split(sep)Divide en una lista
sep.join(iterable)Une elementos en una cadena
.isdigit() / .isalpha() / .isalnum()Verificaciones de tipo de carácter