Clases de caracteres en regex: rangos y negación

Resumen

Las clases de caracteres en regex te dan precisión total cuando los atajos predefinidos como \d o \w se quedan cortos. Aquí aprendes a definir tus propios conjuntos entre corchetes, usar rangos y aplicar la negación para decir "todo menos esto". Es contenido ideal para quien programa, valida datos o procesa texto.

Qué es una clase de caracteres y cómo se define

Una clase de caracteres funciona como un conjunto: cualquier carácter que esté listado dentro de los corchetes empareja uno de ese conjunto, y lo hace de manera individual.

Por ejemplo, [aeiou] significa cualquier vocal minúscula. Si escribes [.,;=] estás diciendo cualquiera de esos signos de puntuación comunes. La clave está en que el motor empareja un carácter a la vez, no la secuencia completa.

¿Qué hace una clase de caracteres en regex? Empareja un solo carácter de los que listas entre corchetes. [aeiou] coincide con cualquier vocal minúscula, una por una.

Para no listar carácter por carácter, existen los rangos con guion. Así defines grupos completos de forma compacta.

Por qué funcionan los rangos con guion

Los rangos funcionan porque cada carácter tiene asignado un número en la tabla ASCII. Cuando escribes un rango, le pides al motor todos los caracteres cuyo código caiga dentro de esos límites.

  • [a-z] cubre todas las letras minúsculas, del código 97 de la a al 122 de la z.
  • [A-Z] cubre todas las mayúsculas.
  • [0-9] cubre todos los dígitos.

Entender la tabla ASCII es lo que te permite predecir exactamente qué va a atrapar tu clase y qué va a dejar fuera.

Por qué el rango A-z casi siempre es un error

Un error clásico es usar [A-z] pensando que dice "todas las letras ASCII". Lo que realmente hace es incluir los caracteres que están entre la Z mayúscula (código 90) y la a minúscula (código 97).

Ese tramo intermedio incluye símbolos como el corchete de apertura, el backslash, el corchete de cierre y el circunflejo. Si usas ese rango para validar nombres, terminas aceptando basura como María\Mary como si fuera un nombre válido.

La forma correcta es escribir dos rangos juntos: [A-Za-z]. Así cubres mayúsculas y minúsculas sin colar los símbolos que viven entre ellas.

¿Por qué [A-z] es incorrecto en regex? Porque incluye símbolos como [, \ y ] que están entre la Z (90) y la a (97) en ASCII. Usa [A-Za-z] en su lugar.

Cómo se comportan los metacaracteres dentro de los corchetes

Algo importante: la mayoría de los metacaracteres dejan de ser especiales cuando están dentro de una clase. Esto simplifica mucho las cosas.

En [.+*?] el motor empareja literalmente un punto, un más, un asterisco o un signo de interrogación. No necesitas escaparlos ahí dentro. Pero hay excepciones que siguen siendo especiales:

  • El backslash sigue funcionando como escape.
  • Un circunflejo al inicio significa negación.
  • Un guion entre dos caracteres significa rango.

Si quieres emparejar un guion literal, ponlo al inicio o al final de la clase, o escápalo. Y si necesitas un corchete dentro de otro corchete, también tienes que escaparlo.

Cómo usar la negación para decir todo menos esto

A veces es más fácil describir lo que no quieres. Ahí entra la negación, que le da la vuelta a la clase entera con un solo carácter.

La regex [^aeiou] empareja cualquier carácter excepto las vocales minúsculas. El circunflejo al principio de la clase actúa como operador de negación. Pero cuidado con su posición: si aparece en cualquier otro lugar, es literal. Por eso [a^b] empareja una a, un símbolo circunflejo o una b.

Con negaciones puedes diseñar estrategias muy potentes. Estos tres patrones se usan muchísimo en la industria:

  1. Procesar archivos CSV: atrapa todo lo que no sea una coma para dividir el texto en columnas.
  2. Aislar textos entre comillas: obtiene todo lo que no sea una comilla.
  3. Extraer etiquetas de un log: busca un corchete abierto y atrapa todo lo que no sea un corchete cerrado, frenando justo antes del final.

Estos patrones muestran por qué la negación es tan útil cuando el contenido que buscas es variable pero el delimitador es fijo.

En qué se diferencia \D de una clase negada

Una duda común es si \D es lo mismo que negar del cero al nueve. La respuesta es casi. En modo Unicode, \d incluye dígitos no ASCII, así que \D también los excluye, mientras que la clase negada [^0-9] solo excluye dígitos ASCII. Si trabajas con datos ASCII, son intercambiables.

Cómo construir clases personalizadas en un caso real

En la práctica, con la herramienta regex101 puedes construir tus propias clases para escenarios concretos. El primer ejemplo es una clase para caracteres hexadecimales, útil porque muchos códigos de error y direcciones web usan ese sistema.

El hexadecimal usa números y letras de la a a la f, en minúscula y mayúscula. La clase queda así:

[0-9a-fA-F]

Son tres rangos en un solo molde. El motor resalta cada número y cada letra de la a a la f, e ignora letras como la s, la r o la o porque no caben en ese molde.

Cómo incluir la ñ y los acentos en tu clase

Aquí viene un detalle que afecta a quien trabaja en español. Si intentas emparejar "año fiscal" con [a-zA-Z], el motor se salta la ñ como si no existiera. Lo mismo pasa con la tilde en Sofía.

Esto ocurre porque la ñ no existe en la tabla ASCII estándar. La solución es ampliar tu clase personalizada agregando esos caracteres a mano:

[a-zA-Zñ]

En cuanto lo agregas, el motor reconoce la ñ. Este ajuste te salva cuando alguien llamado Nicolás Muñoz quiere registrarse. Es un tema que se cierra por completo cuando llegas a Unicode.

Cómo armar una clase negada para logs

El último ejemplo captura el primer corchete y la primera letra de niveles de severidad como info, warn o error, sin atrapar logs vacíos que solo tengan dos corchetes.

Primero escribes un corchete literal, pero como el motor lo interpreta como inicio de clase, tienes que escaparlo. Después quieres cualquier carácter excepto el corchete de cierre, y ahí entra la clase negada. El corchete de cierre dentro de la negación también conviene escaparlo para que el motor lo tome como carácter literal:

[[^]]

El resultado atrapa justo lo que querías: el primer corchete y el primer carácter, ignorando los logs vacíos porque le indicaste que lo que siga no puede ser un corchete de cierre.

Con todo esto ya sabes armar clases con rangos, combinarlas y negarlas, y por qué [A-z] casi siempre es un error. Con saber qué emparejar, la siguiente gran pregunta es cuánto emparejar. ¿Qué patrón vas a construir primero? Cuéntanos en los comentarios.