Indexación y slicing de strings en Python

Un string en Python es una secuencia ordenada de caracteres, y como toda secuencia, puedes acceder a sus elementos por posición. Eso es la indexación: pedirle al string un carácter concreto usando un número entre corchetes. El slicing va un paso más allá: en lugar de un carácter, extraes un fragmento del string especificando dónde empieza, dónde termina y con qué paso avanzan los índices.

Lo primero que hay que tener claro es que en Python no existe un tipo char. Cuando escribes s[0], no obtienes un carácter en el sentido de C o Java, obtienes un string de longitud 1. Todo lo que es texto en Python es str, sin excepciones. Esto simplifica muchísimo el modelo mental: las mismas operaciones que aplicas a un string largo las puedes aplicar al resultado de una indexación.

Los índices negativos son la otra pieza clave antes de ver código. Python permite contar desde el final usando números negativos: s[-1] es el último carácter, s[-2] el penúltimo, y así sucesivamente. No es magia ni sintaxis especial rara: internamente Python suma la longitud del string al índice negativo. s[-1] equivale a s[len(s) - 1]. Es un convenio tan útil que terminas usándolo más que los índices positivos para acceder al final de una secuencia.

Ahora, ¿cuándo usar indexación versus slicing? La indexación (s[i]) es para cuando necesitas exactamente un carácter en una posición conocida. El slicing (s[inicio:fin:paso]) es para extraer subcadenas, hacer transformaciones como invertir el string, o saltar caracteres de forma regular. Y hay algo crítico que no puedes ignorar: los strings son inmutables. Acceder a una posición para leer está bien, pero intentar asignar, s[0] = "H", lanza un TypeError en el momento. Si necesitas modificar un string, tienes que construir uno nuevo.

# Indexación y slicing de strings en Python

texto = "Murciélago"

# ── Indexación básica ──────────────────────────────────────────────────
primero = texto[0]    # "M"
ultimo  = texto[-1]   # "o"
tercero = texto[2]    # "r"

print(f"Primero: {primero!r}, Último: {ultimo!r}, Tercero: {tercero!r}")
# Primero: 'M', Último: 'o', Tercero: 'r'

# s[i] devuelve str de longitud 1, no un tipo especial
print(type(texto[0]))          # <class 'str'>
print(len(texto[0]) == 1)      # True

# ── Slicing s[inicio:fin] ──────────────────────────────────────────────
# fin es exclusivo: s[0:3] extrae los índices 0, 1, 2
primeras_tres = texto[0:3]     # "Mur"
desde_mitad   = texto[5:]      # omitir fin → hasta el final
hasta_mitad   = texto[:5]      # omitir inicio → desde el principio

print(primeras_tres)  # Mur
print(desde_mitad)    # lago   (ajusta según tus pruebas con el string exacto)
print(hasta_mitad)    # Murci

# ── Índices negativos en slicing ──────────────────────────────────────
sin_ultimo      = texto[:-1]   # todo menos el último carácter
ultimas_tres    = texto[-3:]   # los tres últimos caracteres

print(sin_ultimo)    # Murciélag
print(ultimas_tres)  # ago

# ── Step (paso) ────────────────────────────────────────────────────────
cada_dos     = texto[::2]   # un carácter sí, uno no
invertido    = texto[::-1]  # paso negativo recorre el string al revés
solo_pares   = texto[1::2]  # empieza en índice 1, luego cada dos

print(cada_dos)    # Mrié a  (caracteres en posiciones 0,2,4,6,8)
print(invertido)   # ogaléicruM
print(solo_pares)  # uilg

# ── Los slices fuera de rango no lanzan error ──────────────────────────
# Python los recorta silenciosamente al límite del string
print(texto[0:999])   # "Murciélago" completo, sin excepción

# ── Inmutabilidad: esto LANZA TypeError ───────────────────────────────
# texto[0] = "m"   ← TypeError: 'str' object does not support item assignment

# Para "modificar" un string, construyes uno nuevo
modificado = "m" + texto[1:]
print(modificado)  # murciélago

Desglosando las decisiones importantes

El fragmento texto[0:3] devuelve "Mur" y no "Murci" porque el índice de fin es exclusivo. Este convenio viene de que los rangos en Python siguen la convención matemática de intervalo semiabierto [inicio, fin). La ventaja práctica es que fin - inicio te da directamente la longitud del slice, sin tener que hacer fin - inicio + 1 como en otros lenguajes.

Cuando omites inicio o fin, Python usa los extremos del string. texto[:5] y texto[0:5] son idénticos; texto[5:] y texto[5:len(texto)] también. Esta omisión hace que expresiones como texto[:] sean una copia completa del string, aunque con strings (que son inmutables) eso rara vez es necesario.

El paso negativo en texto[::-1] es lo que hace que el slicing recorra el string de derecha a izquierda. Cuando el paso es negativo y omites inicio y fin, Python los interpreta como los extremos opuestos: empieza al final y termina al principio. Es la forma idiomática de invertir una secuencia en Python y es mucho más directa que escribir un bucle.

texto[::2] ilustra el uso de paso para saltar posiciones. Con paso 2 coges una de cada dos letras. Esto tiene aplicaciones reales en procesamiento de datos cuando trabajas con strings que codifican información de forma intercalada, o cuando necesitas submuestrear una secuencia.

El detalle de que los slices fuera de rango no lanzan IndexError —a diferencia de la indexación directa que sí lo hace— es un comportamiento deliberado de Python. texto[0] con un string vacío explota; texto[0:999] con un string corto simplemente devuelve lo que hay. Saber esto evita escribir guardas innecesarias cuando extraes fragmentos de longitud variable.

La inmutabilidad es la restricción que más sorprende a quien viene de otros lenguajes. Python te deja leer cualquier posición, pero el string en memoria nunca cambia. Cuando construyes "m" + texto[1:], Python crea un string completamente nuevo en memoria. No es ineficiencia, es la garantía que permite que los strings sean hasheables y puedan usarse como claves en diccionarios.

Errores que debes conocer

Error: Usar un índice fuera de rango en indexación directa. A diferencia del slicing, s[i] sí lanza IndexError si i está fuera de los límites del string.

# ❌ Wrong
palabra = "hola"
print(palabra[10])   # IndexError: string index out of range

# ✅ Right
if len(palabra) > 10:
    print(palabra[10])

# o usa slicing si sólo quieres el carácter si existe
print(palabra[10:11])  # "" — string vacío, sin excepción

Slicing nunca explota por índices fuera de rango; la indexación directa sí. Usa slicing cuando no estés seguro del tamaño.

Error: Asumir que paso negativo con índices explícitos funciona igual que con índices omitidos.

# ❌ Wrong — intención: invertir "hola", resultado inesperado
s = "hola"
print(s[0:4:-1])   # "" — string vacío porque inicio < fin con paso negativo

# ✅ Right
print(s[3::-1])    # "aloh" — empieza en el último índice válido
print(s[::-1])     # "aloh" — la forma más clara de invertir

Con paso negativo, inicio debe ser mayor que fin. Si usas s[0:4:-1], la condición de avance nunca se cumple y Python devuelve un string vacío sin advertirte.

Error: Intentar modificar un carácter del string directamente, lo que lanza TypeError.

# ❌ Wrong
nombre = "python"
nombre[0] = "P"   # TypeError: 'str' object does not support item assignment

# ✅ Right
nombre = "P" + nombre[1:]   # construye un string nuevo

Los strings son inmutables por diseño; cuando necesites un buffer mutable de caracteres, usa una lista y únela al final con "".join(lista).

35

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio