03 / GUÍAS
Un flujo de trabajo seguro para probar expresiones regulares
Un bucle escribir-probar-refactorizar para expresiones regulares de JavaScript: datos de muestra realistas, higiene contra el backtracking catastrófico, disciplina de anclas, semántica de flags y por qué probar en el navegador mantiene privados los patrones.
El bucle: escribir, probar, refactorizar
Un regex fiable nunca se escribe de una pasada. Empieza con el patrón más pequeño que coincida con un ejemplo real, ejecútalo y luego amplíalo o ajústalo contra el ejemplo siguiente. El texto de muestra es la especificación; el patrón es la implementación.
El bucle es rápido cuando la retroalimentación es instantánea: un probador que reevalúa a cada pulsación convierte cada edición en un experimento con respuesta inmediata, y por eso un espacio de trabajo dedicado supera a reejecutar un script a mano.
- Empieza por una muestraEscribe el patrón contra una muestra concreta, no de memoria: pega una línea real del registro o documento que pretendes analizar.
- Prueba cada ediciónPrueba tras cada cambio: un regex no tiene avisos de compilador, así que la única retroalimentación es con qué coincide y qué se le escapa.
- Refactoriza para lectoresRefactoriza para la lectura una vez que pasa: los grupos de captura con nombre y los grupos sin captura hacen que un patrón funcional sobreviva al siguiente lector.
Respeta el backtracking catastrófico
El motor de regex de JavaScript hace backtracking: cuando una coincidencia falla, reintenta con longitudes distintas para cada cuantificador. Cuantificadores anidados como (a+)+ sobre una cadena que casi coincide hacen explotar exponencialmente el número de reintentos: un patrón que responde al instante con entrada buena puede tardar años con entrada mala. Los atacantes lo llaman ReDoS.
Probador de expresiones regulares JavaScript acota el radio de la explosión: los patrones se ejecutan en un Web Worker dedicado con un presupuesto de 650 milisegundos, y una expresión desbocada se reporta como un tiempo agotado explícito en lugar de congelar la pestaña. Si tu patrón toca ese techo con entrada realista, trátalo como un hallazgo: la misma entrada en producción detendría el bucle de eventos.
- Cuantificadores anidadosLa forma clásica es un grupo cuantificado que contiene un token cuantificado —(a+)+, (\w+)*— donde muchas particiones de la misma cadena satisfacen el patrón interno.
- Alternancia ambiguaLa alternancia ambigua también lo logra: (a|aa)+ da al motor dos formas de coincidir cada carácter extra, duplicando el árbol de búsqueda por carácter.
- Correcciones estructuralesLas correcciones son estructurales: haz inequívoca la coincidencia interna, acótala con límites de longitud explícitos y prueba siempre la entrada que casi coincide, no solo las válidas.
Ancla antes de confiar en la coincidencia
Un patrón que encuentra una subcadena no es un patrón que valida un valor. /\d+/ coincide dentro de abc123xyz; /^\d+$/ solo acepta dígitos. La mayoría de los errores de validación son anclas que faltan, y la mayoría de los errores de extracción son anclas que no deberían estar.
- Inicio y final^ y $ clavan la coincidencia al inicio y al final de la cadena, o de cada línea cuando el flag multilínea está activo, lo que cambia silenciosamente qué significa «toda la entrada».
- Fronteras de palabraLas fronteras de palabra \b evitan que patrones cortos coincidan dentro de palabras más largas: \bcat\b encuentra el animal, no el cat de concatenate.
- Buscar o validarDecide búsqueda frente a validación desde el principio: los patrones de extracción normalmente no quieren anclas; los validadores casi siempre quieren ambas.
Prueba con datos de muestra realistas
Un patrón probado contra tres ejemplos limpios falla en producción con el cuarto real. Construye un conjunto de muestras que refleje la distribución de la entrada: el valor legítimo más largo, la cadena vacía, variantes de espacios, nombres Unicode y el casi-coincidente que casi debería coincidir pero no debe.
- Casi-coincidentesIncluye el casi-coincidente: un patrón de correo debería probarse contra a@b y a b@c.d, no solo contra direcciones bien formadas.
- UnicodeIncluye Unicode donde los datos lo tienen: \w y . cambian de significado con el flag u, y los nombres acentuados rompen supuestos de la era ASCII.
- Reejecuta el conjuntoGuarda el conjunto de muestras junto al patrón; cuando el patrón cambie, vuelve a ejecutar todo el conjunto, no solo el caso que motivó el cambio.
Los flags cambian el lenguaje, no solo la búsqueda
Los flags son parte del significado del patrón. g decide si obtienes la primera coincidencia o todas, i pliega mayúsculas, m reancla ^ y $ a las líneas, s permite al punto cruzar saltos de línea y u cambia el motor a un modo consciente de Unicode con sintaxis más estricta.
El espacio de trabajo evalúa el patrón con los flags que selecciones y lista cada coincidencia con sus desplazamientos de inicio y fin, los grupos de captura numerados y con nombre con sus propias posiciones, y una vista previa de reemplazo en vivo: el cambio de un flag aparece como una diferencia concreta en el resultado, no como teoría.
- g y lastIndexSin g, test() y match() solo ven el primer acierto; con g, un objeto regex arrastra el estado lastIndex y las llamadas repetidas a test() alternan resultados: un error de producción infame.
- s amplía el puntos (dotAll) hace que . coincida con saltos de línea, lo que puede ampliar discretamente el apetito de un patrón viejo al activarlo globalmente.
- u y compañíau hace que las clases y los escapes sean correctos para Unicode y rechaza sintaxis heredada ambigua; el probador también admite d (índices de coincidencia), y (sticky) y v (conjuntos Unicode).
Mantén el patrón y las muestras en local
Los datos de prueba suelen ser datos reales: correos de clientes, líneas de registros internos, identificadores de un informe de incidente. Pegarlos en un probador alojado los envía a la infraestructura de otra persona. Un probador basado en navegador mantiene la sesión en la pestaña: el patrón y el texto de muestra los evalúa el motor de tu propio dispositivo y nunca se transmiten.
El runtime local es explícito sobre sus techos: patrones de hasta 4.096 caracteres, texto de muestra de hasta 100.000 caracteres, reemplazos de hasta 20.000 y como máximo 1.000 coincidencias reportadas por ejecución. Esos límites están dimensionados para desarrollo y depuración; el análisis masivo de registros pertenece a un script local, no a una pestaña del navegador.
Copia fuera solo lo que necesitas —el patrón terminado y la cadena de reemplazo— y deja los datos de muestra donde empezaron: en tu máquina.
Prueba un patrón en localLos datos extraídos suelen acabar en JSON.
Cuando un patrón saca valores de texto crudo, inspecciona y compara la carga resultante con una rutina local determinista.