Saltar al contenido principal

El generador regex

Se usa cuando un valor tiene una forma estricta — un número de teléfono, un SKU, una placa de auto, un token, un código de pedido. Hay demasiadas posibilidades para una lista, y demasiada estructura interna para number: letras, dígitos y separadores en lugares determinados.

Una expresión regular describe esa forma. El generador la lee de izquierda a derecha y llena cada hueco con caracteres aleatorios del conjunto correcto, imprimiendo los literales (guiones, paréntesis, @) tal cual.

Un subconjunto finito y portable

Esto no es el RegExp completo de JavaScript. Es un subconjunto finito que se puede implementar de forma idéntica en cada lenguaje. La única regla dura: el resultado debe tener una longitud acotada, así que *, + y {n,} no están permitidos — siempre se escribe un tope superior explícito.

Un ejemplo desarrollado

Un número de teléfono en formato estadounidense:

<gen type="regex" value="\+1 \([0-9]{3}\) [0-9]{3}-[0-9]{4}"/>
./run phone.tdc
+1 (299) 994-1396
+1 (929) 818-7014
+1 (462) 860-3781
+1 (905) 009-2500
+1 (876) 318-9991

Los paréntesis, los espacios y los guiones son literales (la barra invertida antes de ( y ) los convierte en caracteres comunes). El \+1 es un +1 literal, y los grupos [0-9]{…} son huecos que reciben dígitos aleatorios. La forma es siempre la misma; los valores cambian.

Todos los ejemplos de esta página se renderizan con seed="demo". Pero el sorteo lo deciden dos cosas, y la segunda sorprende: la semilla y el nombre de la secuencia. Cada columna saca de su propio flujo, derivado de ambos, para que agregar una columna nunca desplace a las de al lado — así que el mismo patrón bajo <sequence name="Phone"> y bajo <sequence name="V"> da strings distintos con la misma semilla. Si copia un patrón de esta página a una secuencia con otro nombre, espere otros valores.

Los valores de salida son ilustrativos; los strings exactos pueden cambiar según la versión del core, pero la forma nunca.

Otras formas de todos los días:

TareaPatrónEjemplo
SKU[A-Z]{3}-[0-9]{4}SAH-0136
Placa (EE. UU.)[0-9][A-Z]{3}[0-9]{3}7KLM042
Token hex de 32 caracteres[A-F0-9]{32}5AE5ABF3F7040BEB966D65A23EB7C1EC
Correo de pruebauser_[a-z0-9]{8}@test\.(com|org)user_zak0bdnw@test.com

Ese mismo SKU, renderizado completo:

<gen type="regex" value="[A-Z]{3}-[0-9]{4}"/>
./run sku.tdc
FZY-9944
YHZ-8189
LRG-8608
YAO-0097
WTR-3189

Cuándo el regex simple es la herramienta correcta

Use type="regex" para describir la forma de un string cuando no se necesitan proporciones exactas dentro de él. Una alternancia como (com|org) se elige al azar y de forma independiente en cada fila — está bien cuando el reparto exacto de las variantes no importa.

Buenos trabajos para el regex simple:

  • un ID técnico: [A-Z]{2}[0-9]{6};
  • un correo de prueba seguro: user_[a-z0-9]{8}@test\.(com|org);
  • un código con un bloque que se repite: ([0-9]{3})-[A-Z]{2}-\1;
  • un token de longitud fija: [A-F0-9]{32}.

Si se necesitan porciones exactas de variantes dentro del string (digamos, exactamente 70 % con un prefijo), el regex simple no lo hace — eche mano de advanced_regex:

<gen type="advanced_regex" value="(?%{70:US;20:CA;10:UK})-[0-9]{6}"/>

La sintaxis de un vistazo

ConstrucciónEjemploGenera
LiteralesABC-42Exactamente esos caracteres
Caracteres escapados\.\+\(\)\\Punto, más, paréntesis, barra invertida
Clase de caracteres[ABC], [a-z], [A-Z0-9]Un carácter del conjunto
Rango Unicode BMP[а-я], [א-ת], [ぁ-ゖ]Un carácter del rango
Alfabeto con nombre\a{kana.hiragana}Un carácter de un alfabeto incorporado
Clase negada[^0-9]Un carácter ASCII imprimible, salvo esos
Clase abreviada\d, \w, \sDígito, carácter de palabra, espacio o tabulador
Abreviada inversa\D, \W, \SLo inverso de lo anterior
Cualquier carácter.Un carácter ASCII imprimible
Alternanciacat|dogcat o dog
Grupo(cat|dog)Agrupación y captura
Grupo sin captura(?:cat|dog)Agrupación sin captura
Retrorreferencia([0-9]{3})-\1Repite un grupo ya generado
Grupo con nombre(?<code>[A-Z]{2})Agrupación y captura, bajo un nombre
Referencia por nombre\k<code>Repite un grupo por su nombre
Condicional(?(code)-|/)Una rama u otra, según el grupo
OpcionalAB?CAC o ABC
Repetición exacta[A-Z]{4}Exactamente 4
Repetición por rango[A-Z]{2,5}De 2 a 5
Anclas^ABC$Ancho cero; el resultado es ABC

El resto de esta página es la misma lista, pero con salida real debajo de cada entrada.

Clases de caracteres

[…] toma un carácter al azar del conjunto. Un rango a-z es la forma corta de decir todas las letras de la a a la z.

<gen type="regex" value="[ABC]{6}"/> <!-- solo A, B, C -->
<gen type="regex" value="[a-z]{6}"/> <!-- latinas minúsculas -->
<gen type="regex" value="[A-Z0-9]{6}"/> <!-- mayúsculas y dígitos -->
./run demo.tdc
[ABC]{6}      [a-z]{6}      [A-Z0-9]{6}
CAACAA        sahtbc        ZAK0BD
CCACAC        rvhyfr        Y3K7HY
AAABAC        ggaqby        IJBWC8

Cada hueco se elige de forma independiente, así que las letras se repiten en [ABC]{6} — son seis caracteres aleatorios por separado, no una selección sin repetición.

Clases abreviadas — \d \w \s

Conjuntos listos para usar: \d es un dígito [0-9], \w es una letra, un dígito o _, y \s es un espacio o un tabulador.

<gen type="regex" value="\d{6}"/>
<gen type="regex" value="\w{8}"/>
./run demo.tdc
\d{6}      \w{8}
702701     tBSvCGXm
682926     qyR7NqAz
220609     OQBoE7TG

\s es invisible en la salida, así que aquí los espacios y tabuladores se muestran como <SP> y <TAB> (en la salida real son espacios en blanco comunes):

<gen type="regex" value="A\sB\sC"/>
./run demo.tdc
A<TAB>B<TAB>C
A<SP>B<TAB>C
A<SP>B<SP>C

Clases negadas — [^…] \D \W \S

[^0-9] y \D dan cualquier carácter ASCII imprimible excepto los listados. Son equivalentes y producen la misma salida con la misma semilla:

<gen type="regex" value="[^0-9]{6}"/>
<gen type="regex" value="\D{6}"/>
./run demo.tdc
[^0-9]{6}    \D{6}
f"Bi#)       f"Bi#)
cnAz<b       cnAz<b
@!"%zR       @!"%zR

Note que el conjunto es todo el ASCII imprimible (letras, dígitos, puntuación), no solo letras. Si lo que quiere es únicamente una letra que no sea dígito, escríbalo explícitamente: [A-Za-z].

Cualquier carácter — .

El punto es un carácter ASCII imprimible (el mismo conjunto que \D, sin exclusiones):

<gen type="regex" value=".{8}"/>
./run demo.tdc
3|{Dy{JH
z9{Gl0mx
J^9Pp_%r
z!Tx'){i

Cuantificadores — cuántas veces

{n} es exactamente n; {n,m} es de n a m (al azar); ? es cero o uno (así que AB?C es AC o ABC).

<gen type="regex" value="[A-Z]{4}"/> <!-- exactamente 4 -->
<gen type="regex" value="[A-Z]{2,5}"/> <!-- de 2 a 5 -->
<gen type="regex" value="AB?C"/> <!-- B opcional -->
./run demo.tdc
[A-Z]{4}    [A-Z]{2,5}    AB?C
SAHT        SAHTB         ABC
RVHY        RVH           AC
GGAQ        GG            AC

Cambie el cuantificador y cambia la longitud — mismo esqueleto (letras y luego dígitos), distinto tamaño:

<gen type="regex" value="[A-Z]{2}[0-9]{4}"/> <!-- corto -->
<gen type="regex" value="[A-Z]{3}[0-9]{8}"/> <!-- largo -->
./run demo.tdc
[A-Z]{2}[0-9]{4}    [A-Z]{3}[0-9]{8}
SA7013              SAH01363846
RV9260              RVH26087805
GG6093              GGA09313068

Alternancia y grupos — | (…) (?:…)

cat|dog elige una variante al azar en cada fila. Los paréntesis agrupan variantes para poder pegarles un sufijo o un cuantificador.

<gen type="regex" value="cat|dog"/> <!-- alternancia -->
<gen type="regex" value="(cat|dog)-[0-9]{2}"/> <!-- grupo + sufijo -->
<gen type="regex" value="(?:cat|dog)[0-9]"/> <!-- sin captura -->
./run demo.tdc
cat|dog    (cat|dog)-[0-9]{2}    (?:cat|dog)[0-9]
dog        dog-02               dog7
cat        cat-82               cat6
cat        cat-20               cat2
dog        dog-77               dog2

Un grupo simple (…) recuerda su elección (la captura), así que se puede volver a él con \1. (?:…) agrupa sin recordar — úselo cuando no necesite la captura.

Aleatorio, no exacto

cat y dog salen de forma despareja — es una elección aleatoria, no una proporción exacta. Para exactamente 70/30, use advanced_regex.

Anclas — ^ $

^ (inicio) y $ (fin) son de ancho cero: el generador las acepta pero no agregan nada a la salida. ^[A-Z]{3}$ produce las mismas tres letras que [A-Z]{3}:

<gen type="regex" value="^[A-Z]{3}$"/>
./run demo.tdc
FZY
YHZ
LRG

Escapado

Convierta un metacarácter de regex en un literal común con \:

<gen type="regex" value="\.\+\(\)\[\]\{\}\\"/>

Aquí el string generado es constante (no hay huecos aleatorios):

./run demo.tdc
.+()[]{}\

Dentro de una clase de caracteres, un guion es un literal cuando va primero o último — entonces es solo el carácter -, no un rango:

<gen type="regex" value="[-A-C]{8}"/>
<gen type="regex" value="[A-C-]{8}"/>
./run demo.tdc
[-A-C]{8}    [A-C-]{8}
B-AB--AB     CABCAABC
BCAC-B-C     C-B-ACA-
-A-B-CA-     ABACA-BA

El conjunto aquí son cuatro caracteres: A, B, C y -.

Alfabetos Unicode

Las clases de caracteres no están limitadas a ASCII. La misma maquinaria acepta cualquier rango Unicode BMP y cualquier alfabeto con nombre incorporado, así que el generador se localiza sin casos especiales. Empiece por la escritura latina que sus datos suelen necesitar — un rango simple cubre directamente las letras acentuadas de Europa occidental:

<gen type="regex" value="[a-zà-ÿ]{8}"/> <!-- latinas + acentos -->
./run demo.tdc
lþýwüýzy
ýpþyôkõü
zìpãöídø

Los ejemplos de abajo son una demostración deliberada de Unicode y localización — escrituras no latinas escritas de la misma manera. Los rangos BMP simples funcionan directamente dentro de una clase de caracteres:

<gen type="regex" value="[а-я]{8}"/> <!-- cirílico -->
<gen type="regex" value="[א-ת]{6}"/> <!-- hebreo -->
./run demo.tdc
[а-я]{8}      [א-ת]{6}
цайчбглу      ףאחפבג
хщиюжхаъ      עץחשוע
зибфвюкг      זחאסבש

Para configuraciones reales, los alfabetos con nombre son más claros — están documentados, validados por su nombre y pueden incluir caracteres incómodos de expresar como rango (como la ё rusa):

<gen type="regex" value="\a{cyrillic.ru.letters}{10}"/>
<gen type="regex" value="\a{kana.hiragana}{8}"/>
./run demo.tdc
\a{cyrillic.ru.letters}{10}    \a{kana.hiragana}{8}
нБСпВЖЧжХч                     まぃすめいおちふ
куСьНкАупф                     ほゆすをこぺあょ

Se pueden mezclar alfabetos dentro de una misma clase — el carácter se toma entonces de la unión:

<gen type="regex" value="[\a{arabic.letters}\a{hebrew.letters}]{6}"/>
./run demo.tdc
خררػקר
קسרؾםح
ؿדسلנה

El escape \a{name} es un carácter de ese alfabeto y se comporta como cualquier átomo — repítalo con {n} o {n,m}; dentro de una clase agrega el alfabeto completo al conjunto. La lista completa de nombres está en la página Symbol.

nota

Las clases negadas ([^...]), \D, \W, \S y . invierten únicamente contra el conjunto ASCII imprimible. Para Unicode, escriba un conjunto positivo con \a{name}.

Retrorreferencias

Una retrorreferencia ata entre sí partes de un string: \1 repite lo que el primer grupo (…) ya generó.

<gen type="regex" value="([0-9]{3})-[A-Z]{2}-\1"/>
./run demo.tdc
299-YZ-299
929-UE-929
462-VR-462
905-BC-905

Los primeros y los últimos tres dígitos siempre coinciden — ese es el bloque capturado. Así se construyen números de documento donde una sección se repite.

Una referencia solo puede apuntar a un grupo ya generado a su izquierda; una referencia hacia adelante es un error:

<gen type="regex" value="\1([0-9]{3})"/>
./run bad.tdc
error: invalid regex generator pattern: backreference "\1" points to
a group that is not generated yet

Si la captura está dentro de una repetición, la retrorreferencia usa el último valor que ese grupo generó:

<gen type="regex" value="([A-Z]){3}-\1"/>
./run demo.tdc
FZY-Y
YHZ-Z
LRG-G

Aquí ([A-Z]){3} corre el grupo tres veces, y \1 repite solo la tercera letra que produjo.

Grupos con nombre — (?<name>…)

Un grupo puede llevar un nombre, y \k<name> lo repite. Es el mismo grupo que repite \1: el nombre es una segunda forma de llegar a un grupo, no un segundo grupo.

<gen type="regex" value="(?<code>[A-Z]{2})-[0-9]{3}-\k<code>"/>
./run demo.tdc
FZ-399-FZ
YH-481-YH
LR-586-LR
YA-900-YA

Un nombre hace legible un patrón largo, y es lo que lee un condicional. Tres reglas:

  • Un nombre empieza por una letra o _ y lleva letras, dígitos y _.
  • Un nombre se usa una sola vez. Dos grupos bajo un mismo nombre convertirían \k<name> en un volado, resuelto por el que el analizador registró al final.
  • \k<name> solo puede nombrar un grupo ya cerrado — la misma regla que sigue \1.

(?<=…) y (?<!…) siguen siendo lookbehind y siguen rechazados. Ninguno es un grupo cuyo nombre empiece por =.

Condicionales — (?(name)sí|no)

Un condicional pregunta si un grupo produjo algo y escribe una rama u otra. Así se pone un separador solo cuando hay algo que separar:

<gen type="regex" value="(?<area>0[1-9]{2})?(?(area)-|8 )[0-9]{4}"/>
./run demo.tdc
099-9944
039-8189
063-8608
016-0097
8 7683
8 0194

El código de área es opcional. Donde aparece lo sigue un -; donde no, la fila empieza con 8 . Sin un condicional eso son dos configuraciones, o un <switch>.

  • El condicional no gasta azar. Lee una decisión que el grupo ya tomó, así que añadir uno a un patrón deja el resto de los valores de la columna donde estaban.
  • La segunda rama se puede omitir: (?(area)-) escribe el - o nada en absoluto.
  • Un grupo también se puede probar por número — ([0-9]{3})?(?(1)-).
  • Dos ramas, no más. Una tercera se rechaza en vez de descartarse en silencio; si hace falta una elección dentro de una rama, agrúpela: (?(area)(?:x|y)|z).

Un condicional solo puede probar un grupo que esté a su izquierda, por la misma razón que una retrorreferencia: el grupo todavía no ha producido nada, así que esa rama nunca podría tomarse.

<gen type="regex" value="(?(area)-)(?<area>[0-9]{3})"/>
./run bad.tdc
error: invalid regex generator pattern: conditional group "(?(area)...)"
tests group "area", which is not generated yet

El límite de longitud — regex_max_length

Cada resultado se contrasta con regex_max_length (por omisión 32). Un patrón que pudiera excederlo se rechaza antes de generar:

<gen type="regex" value="[A-Z0-9]{40}"/>
./run token.tdc
error: invalid regex generator pattern: regex can produce 40 characters,
which exceeds regex_max_length=32

Suba el tope para toda la configuración en <tdc>. Use esto cuando una configuración tiene varios patrones largos y quiere fijar el techo en un solo lugar:

<tdc regex_max_length="64">
<env count="5" seed="demo">
<sequence name="Token"><gen type="regex" value="[A-Z0-9]{40}"/></sequence>
</env>
<block>
<line><data>${{Token}}</data></line>
</block>
</tdc>
./run token.tdc
MURI40FXS16A2ABROOBQFGMSDBLWP3TCDTA16VVK
NPJ3PVSU1NGARTRDQHT92IHGWJZVUST4531IOEAW
66WWVKTAA2XWUQJBJA8P0SNZ6W3Q75R3CP12JIXW

O fíjelo localmente, solo en este generador, cuando un único campo es la excepción y no quiere aflojar el techo en todos los demás:

<gen type="regex" value="[A-Z0-9]{40}" regex_max_length="40"/>
./run token.tdc
H88N88QPEO7XQU8Y3HSZVUVHBRNYDL22R5UYULFK
8J8P2G372CFQ09IGKO4DBWVJ7OX20A24XAGFOCA2
PXJS4YC5M13GUWUS7BVTYLT6Y3YFXOC04TLQUFZF

regex_max_length no vuelve finita una regex infinita — solo permite que un resultado ya finito sea más largo.

Qué no está permitido

No permitidoPor quéUse en su lugar
*Sin tope superior{0,n}
+Sin tope superior{1,n}
{n,}Sin tope superior{n,m}
Perezosos *?, ??Semántica de búsqueda, no de generaciónEscriba el rango que quiere
Lookahead / lookbehindInspeccionan texto existente, no lo construyenMueva la condición al DSL
\p{...} / \P{...}Las propiedades Unicode aún no son portables\a{name} o una clase explícita
\n / \rLa generación multilínea vive en otro ladoUse <line>s separados

Por ejemplo, + se rechaza de inmediato:

<gen type="regex" value="[a-z]+"/>
./run bad.tdc
error: invalid regex generator pattern: unbounded "+" quantifier is not
allowed; use "{1,n}"

Proporciones exactas

El regex simple no fija porcentajes dentro de la expresión — (cat|dog) es aleatorio, no exactamente 70/30. Para porciones exactas use:

Vea también