El módulo glob suele utilizarse para localizar archivos mediante patrones como *.py, datos/**/*.csv o informe-??.pdf. La función glob.translate() permite transformar un patrón glob en una expresión regular. Esto resulta útil cuando deseas conservar la sintaxis sencilla de los globs, pero necesitas filtrar rutas procedentes de una API, un archivo comprimido, una base de datos, un almacenamiento en la nube o una colección en memoria.
En esta guía aprenderás cómo funciona glob.translate, en qué se diferencia de fnmatch.translate, cómo tratar búsquedas recursivas, archivos ocultos, separadores de rutas y validación segura.
Qué hace glob.translate
glob.translate(pattern) devuelve una cadena de expresión regular compatible con el módulo re. Esa expresión puede compilarse una sola vez y reutilizarse para comparar muchas rutas.
import glob
import re
regex = re.compile(glob.translate("src/**/*.py", recursive=True))
rutas = [
"src/app.py",
"src/api/routes.py",
"tests/test_app.py",
]
seleccionadas = [ruta for ruta in rutas if regex.match(ruta)]
print(seleccionadas)
El patrón se interpreta como una ruta y no como texto arbitrario. Por eso, los separadores de directorios son importantes y un asterisco normal no suele atravesarlos.
Patrones glob frente a expresiones regulares
Los globs fueron diseñados para ser simples. El asterisco representa una secuencia de caracteres, el signo de interrogación representa un carácter y los corchetes definen una clase. Las expresiones regulares ofrecen mucho más control, pero también son más difíciles de leer y mantener.
glob.translate crea un puente práctico entre ambas ideas. Los usuarios pueden escribir un filtro sencillo y el programa puede trabajar con una expresión regular compilada.
Búsqueda recursiva con doble asterisco
Cuando se utiliza recursive=True, el patrón ** puede representar varios niveles de directorios.
patron = "proyecto/**/test_*.py"
regex = re.compile(glob.translate(patron, recursive=True))
for ruta in rutas:
if regex.match(ruta):
print(ruta)
Sin la opción recursiva, no conviene asumir que ** recorrerá cualquier profundidad. Configura la opción de forma explícita para que el comportamiento sea claro.
Archivos y directorios ocultos
En sistemas Unix, los nombres que comienzan con punto son ocultos. La opción include_hidden controla si los comodines pueden coincidir con esos componentes. Esta diferencia es importante en analizadores de proyectos, copias de seguridad e indexadores, porque carpetas como .git, .venv y .cache pueden contener miles de archivos.
regex = re.compile(
glob.translate("**/*.toml", recursive=True, include_hidden=False)
)
Incluso si solo comparas cadenas, conservar esta regla ayuda a reproducir el comportamiento esperado del módulo glob.
Separadores personalizados
La función puede trabajar con separadores específicos. Esto es útil cuando las rutas proceden de archivos ZIP, servicios remotos o almacenamiento de objetos. Los miembros de un ZIP suelen usar barras normales incluso en Windows.
regex = re.compile(
glob.translate("assets/**/*.png", recursive=True, seps="/")
)
Fijar el separador permite obtener resultados previsibles en diferentes sistemas operativos y simplifica las pruebas automatizadas.
glob.translate frente a fnmatch.translate
fnmatch.translate está orientado principalmente a nombres, mientras que glob.translate entiende segmentos de rutas. En una ruta, el separador funciona como límite especial. En una coincidencia de nombre, el valor suele tratarse como una sola secuencia.
Usa fnmatch para nombres simples como foto-*.jpg. Usa glob.translate cuando intervienen directorios, recursión, componentes ocultos o separadores configurables.
Compilar la expresión una sola vez
Si el mismo patrón se aplicará a miles de elementos, compila la expresión una vez y reutilízala.
def crear_filtro(patron, *, recursive=False):
expresion = glob.translate(patron, recursive=recursive)
return re.compile(expresion)
filtro = crear_filtro("logs/**/*.json", recursive=True)
resultados = [ruta for ruta in rutas if filtro.match(ruta)]
Si la aplicación recibe muchos patrones dinámicos, puedes utilizar una caché limitada. Evita almacenar un número ilimitado de expresiones compiladas.
Validación y seguridad
Los patrones glob no ejecutan código, pero un patrón demasiado amplio puede generar problemas de rendimiento. Una búsqueda que abarque todo un servidor, un bucket o un árbol enorme puede consumir demasiado tiempo y memoria.
En una aplicación web, no permitas que un patrón no confiable recorra cualquier carpeta. Restringe el directorio raíz, la profundidad, la longitud del patrón, el tiempo de ejecución y la cantidad de resultados. Cuando se trabaja con listas en memoria, también conviene limitar el tamaño de entrada.
Ejemplo con objetos de almacenamiento en la nube
Supongamos que una API devuelve claves de objetos y necesitas seleccionar imágenes de un cliente concreto.
objetos = [
"clientes/acme/logo.png",
"clientes/acme/docs/manual.pdf",
"clientes/acme/screens/home.webp",
"clientes/otro/logo.png",
]
patron = "clientes/acme/**/*.[pw][ne][gb]"
regex = re.compile(glob.translate(patron, recursive=True, seps="/"))
filtrados = [objeto for objeto in objetos if regex.match(objeto)]
Para muchas extensiones, puede ser más claro combinar un filtro de ruta con una comprobación del sufijo mediante pathlib. La claridad suele ser mejor que un patrón excesivamente ingenioso.
Normalización con pathlib
pathlib ofrece una API orientada a objetos. Puedes normalizar rutas remotas con PurePosixPath antes de aplicar el regex.
from pathlib import PurePosixPath
normalizadas = [PurePosixPath(ruta).as_posix() for ruta in objetos]
filtradas = [ruta for ruta in normalizadas if regex.match(ruta)]
Consulta también nuestros contenidos sobre pathlib en Python, expresiones regulares, el módulo os y archivos grandes.
Pruebas recomendadas
Incluye casos con archivos en la raíz, rutas profundas, componentes ocultos, separadores distintos, espacios, extensiones en mayúsculas, valores vacíos y coincidencias parciales.
casos = {
"src/main.py": True,
"src/api/main.py": True,
"src/.cache/main.py": False,
"tests/main.py": False,
}
filtro = re.compile(glob.translate("src/**/*.py", recursive=True))
for ruta, esperado in casos.items():
assert bool(filtro.match(ruta)) is esperado
Las pruebas son especialmente importantes cuando los patrones se guardan en archivos de configuración, porque un pequeño cambio puede incluir o excluir muchos elementos sin producir un error visible.
Errores comunes
Un error frecuente es esperar que * atraviese separadores. Otro es olvidar el tratamiento especial de nombres ocultos. También es común aplicar rutas de Windows a un filtro creado para rutas POSIX sin normalizar previamente.
Evita recompilar el mismo patrón dentro de un bucle. Traduce y compila antes de iterar. Tampoco dependas de detalles internos de la expresión generada; controla el comportamiento mediante los parámetros públicos.
Cuándo conviene usar glob.translate
Es una buena opción cuando necesitas una sintaxis amigable para usuarios y quieres aplicar el filtro fuera de una búsqueda directa en disco. Algunos casos son listados de almacenamiento en la nube, manifiestos ZIP, reglas de backup, herramientas de build, indexadores de código, descubrimiento de pruebas y pipelines de recursos.
Para consultar los detalles exactos, revisa la documentación oficial de glob y la documentación de re. Verifica la versión de Python cuando mantengas compatibilidad con intérpretes antiguos.
Conclusión
glob.translate combina la legibilidad de los patrones glob con la flexibilidad de las expresiones regulares compiladas. Si entiendes la recursión, los separadores, los archivos ocultos, la validación y las pruebas, puedes construir filtros portables y previsibles. Mantén los patrones limitados, normaliza las rutas y aplica restricciones cuando la entrada provenga de usuarios o sistemas externos.







