The regex generator
Use it when a value has a strict shape — a phone number, a SKU, a license
plate, a token, an order code. There are too many possibilities for a list, and
too much internal structure for number: letters, digits, and
separators in specific places.
A regular expression describes that shape. The generator reads it left to right and
fills each slot with random characters from the matching set, printing literals
(dashes, parentheses, @) as-is.
This is not the full JavaScript RegExp. It's a finite subset that can be
implemented identically in every language. The one hard rule: the
result must have a bounded length, so *, +, and {n,} are not allowed —
you always write an explicit upper bound.
A worked example
A US-format phone number:
<gen type="regex" value="\+1 \([0-9]{3}\) [0-9]{3}-[0-9]{4}"/>
+1 (299) 994-1396 +1 (929) 818-7014 +1 (462) 860-3781 +1 (905) 009-2500 +1 (876) 318-9991
The parentheses, spaces, and dashes are literals (the backslash before ( and )
makes them ordinary characters). The \+1 is a literal +1, and the [0-9]{…}
groups are slots that get random digits. The shape is always the same; only the
values differ.
Every example on this page is rendered with seed="demo". Two things decide the draw,
though, and the second one surprises people: the seed and the sequence's name. Each
column draws from its own stream, derived from both, so that adding a column never shifts
the ones beside it — which means the same pattern under <sequence name="Phone"> and
under <sequence name="V"> gives different strings, on the same seed. Copy a pattern out
of this page into a differently named sequence and expect different values.
Output values are illustrative; the exact strings can differ by core version, but the shape never does.
Other everyday shapes:
| Task | Pattern | Example |
|---|---|---|
| SKU | [A-Z]{3}-[0-9]{4} | SAH-0136 |
| Plate (US) | [0-9][A-Z]{3}[0-9]{3} | 7KLM042 |
| 32-char hex token | [A-F0-9]{32} | 5AE5ABF3F7040BEB966D65A23EB7C1EC |
| Test email | user_[a-z0-9]{8}@test\.(com|org) | user_zak0bdnw@test.com |
That same SKU, rendered in full:
<gen type="regex" value="[A-Z]{3}-[0-9]{4}"/>
FZY-9944 YHZ-8189 LRG-8608 YAO-0097 WTR-3189
When plain regex is the right tool
Use type="regex" to describe the shape of one string when you don't need
exact proportions inside it. An alternation like (com|org) is chosen randomly
and independently on each row — fine when the exact split of variants doesn't
matter.
Good fits for plain regex:
- a technical ID:
[A-Z]{2}[0-9]{6} - a safe test email:
user_[a-z0-9]{8}@test\.(com|org) - a code with a repeating block:
([0-9]{3})-[A-Z]{2}-\1 - a fixed-length token:
[A-F0-9]{32}
If you need exact shares of variants inside the string (say, exactly 70% with
one prefix), plain regex won't do it — reach for
advanced_regex:
<gen type="advanced_regex" value="(?%{70:US;20:CA;10:UK})-[0-9]{6}"/>
Syntax at a glance
| Construct | Example | Generates |
|---|---|---|
| Literals | ABC-42 | Exactly those characters |
| Escaped characters | \.\+\(\)\\ | Dot, plus, parens, backslash |
| Character class | [ABC], [a-z], [A-Z0-9] | One character from the set |
| Unicode BMP range | [а-я], [א-ת], [ぁ-ゖ] | One character from the range |
| Named alphabet | \a{kana.hiragana} | One character from a built-in alphabet |
| Negated class | [^0-9] | A printable ASCII character, except those |
| Shorthand class | \d, \w, \s | Digit, word char, space/tab |
| Inverse shorthand | \D, \W, \S | The inverse of the above |
| Any character | . | One printable ASCII character |
| Alternation | cat|dog | cat or dog |
| Group | (cat|dog) | Grouping and capture |
| Non-capturing group | (?:cat|dog) | Grouping without capture |
| Backreference | ([0-9]{3})-\1 | Repeats an already-generated group |
| Named group | (?<code>[A-Z]{2}) | Grouping and capture, under a name |
| Named backreference | \k<code> | Repeats a group by name |
| Conditional | (?(code)-|/) | One branch or the other, by the group |
| Optional | AB?C | AC or ABC |
| Exact repeat | [A-Z]{4} | Exactly 4 |
| Range repeat | [A-Z]{2,5} | 2 to 5 |
| Anchors | ^ABC$ | Zero-width; the result is ABC |
The rest of this page is the same list, but with real output under each one.
Character classes
[…] takes one random character from the set. A range a-z is shorthand for "every
letter from a to z".
<gen type="regex" value="[ABC]{6}"/> <!-- only A, B, C -->
<gen type="regex" value="[a-z]{6}"/> <!-- lowercase latin -->
<gen type="regex" value="[A-Z0-9]{6}"/> <!-- uppercase and digits -->
[ABC]{6} [a-z]{6} [A-Z0-9]{6}
CAACAA sahtbc ZAK0BD
CCACAC rvhyfr Y3K7HY
AAABAC ggaqby IJBWC8Each slot is chosen independently, so letters repeat in [ABC]{6} — it's six
separate random characters, not a draw without replacement.
Shorthand classes — \d \w \s
Ready-made sets: \d is a digit [0-9], \w is a letter/digit/_, \s is a space
or tab.
<gen type="regex" value="\d{6}"/>
<gen type="regex" value="\w{8}"/>
\d{6} \w{8}
702701 tBSvCGXm
682926 qyR7NqAz
220609 OQBoE7TG\s is invisible in the output, so spaces and tabs are shown here as <SP> and
<TAB> (in real output they're ordinary whitespace):
<gen type="regex" value="A\sB\sC"/>
A<TAB>B<TAB>C A<SP>B<TAB>C A<SP>B<SP>C
Negated classes — [^…] \D \W \S
[^0-9] and \D give any printable ASCII character except the listed ones.
They're equivalent and produce the same output on the same seed:
<gen type="regex" value="[^0-9]{6}"/>
<gen type="regex" value="\D{6}"/>
[^0-9]{6} \D{6}
f"Bi#) f"Bi#)
cnAz<b cnAz<b
@!"%zR @!"%zRThe set is the whole printable ASCII range (letters, digits,
punctuation), not just letters. If you want letters only, spell it out: [A-Za-z].
Any character — .
The dot is one printable ASCII character (the same set as \D, with no exclusions):
<gen type="regex" value=".{8}"/>
3|{Dy{JH
z9{Gl0mx
J^9Pp_%r
z!Tx'){iQuantifiers — how many times
{n} is exactly n; {n,m} is n to m (random); ? is zero or one (so AB?C
is AC or ABC).
<gen type="regex" value="[A-Z]{4}"/> <!-- exactly 4 -->
<gen type="regex" value="[A-Z]{2,5}"/> <!-- 2 to 5 -->
<gen type="regex" value="AB?C"/> <!-- B optional -->
[A-Z]{4} [A-Z]{2,5} AB?C
SAHT SAHTB ABC
RVHY RVH AC
GGAQ GG ACChange the quantifier and the length changes — same "skeleton" (letters, then digits), different size:
<gen type="regex" value="[A-Z]{2}[0-9]{4}"/> <!-- short -->
<gen type="regex" value="[A-Z]{3}[0-9]{8}"/> <!-- long -->
[A-Z]{2}[0-9]{4} [A-Z]{3}[0-9]{8}
SA7013 SAH01363846
RV9260 RVH26087805
GG6093 GGA09313068Alternation and groups — | (…) (?:…)
cat|dog picks one variant at random on each row. Parentheses group the
variants so you can attach a suffix or a quantifier.
<gen type="regex" value="cat|dog"/> <!-- alternation -->
<gen type="regex" value="(cat|dog)-[0-9]{2}"/> <!-- group + suffix -->
<gen type="regex" value="(?:cat|dog)[0-9]"/> <!-- no capture -->
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 dog2A plain group (…) remembers its choice (capture) so you can refer back to it with
\1. (?:…) groups without remembering — use it when you don't need the capture.
cat and dog come out unevenly — this is a random choice, not exact
proportions. For exactly 70/30, use advanced_regex.
Anchors — ^ $
^ (start) and $ (end) are zero-width: the generator accepts them but they add
nothing to the output. ^[A-Z]{3}$ produces the same three letters as [A-Z]{3}:
<gen type="regex" value="^[A-Z]{3}$"/>
FZY YHZ LRG
Escaping
Turn a regex metacharacter into an ordinary literal with \:
<gen type="regex" value="\.\+\(\)\[\]\{\}\\"/>
The generated string is constant here (there are no random slots):
.+()[]{}\Inside a character class, a dash is a literal when it's first or last — then it's
just the character -, not a range:
<gen type="regex" value="[-A-C]{8}"/>
<gen type="regex" value="[A-C-]{8}"/>
[-A-C]{8} [A-C-]{8}
B-AB--AB CABCAABC
BCAC-B-C C-B-ACA-
-A-B-CA- ABACA-BAThe set here is four characters: A, B, C, and -.
Unicode alphabets
Character classes aren't limited to ASCII. The same machinery accepts any Unicode BMP range and any built-in named alphabet, so the generator localizes without special cases. Start with the Latin script most data needs — a plain range covers Western European accented letters directly:
<gen type="regex" value="[a-zà-ÿ]{8}"/> <!-- latin + accents -->
lþýwüýzy ýpþyôkõü zìpãöídø
The examples below are a deliberate Unicode/localization demonstration — non-Latin scripts written exactly the same way. Plain BMP ranges work directly inside a character class:
<gen type="regex" value="[а-я]{8}"/> <!-- cyrillic -->
<gen type="regex" value="[א-ת]{6}"/> <!-- hebrew -->
[а-я]{8} [א-ת]{6}
цайчбглу ףאחפבג
хщиюжхаъ עץחשוע
зибфвюкг זחאסבשFor real configs, named alphabets are clearer — they're documented, validated by
name, and can include characters that are awkward to express as a range (like the
Russian ё):
<gen type="regex" value="\a{cyrillic.ru.letters}{10}"/>
<gen type="regex" value="\a{kana.hiragana}{8}"/>
\a{cyrillic.ru.letters}{10} \a{kana.hiragana}{8}
нБСпВЖЧжХч まぃすめいおちふ
куСьНкАупф ほゆすをこぺあょYou can mix alphabets inside one class — the character is then drawn from the union of them:
<gen type="regex" value="[\a{arabic.letters}\a{hebrew.letters}]{6}"/>
خררػקר קسרؾםح ؿדسلנה
The escape \a{name} is one character from that alphabet, and it behaves like any
other atom — repeat it with {n} or {n,m}; inside a class it adds the whole
alphabet to the set. The full list of names is on the
Symbol page.
Negated classes ([^...]), \D, \W, \S, and . invert against the printable
ASCII set only. For Unicode, spell out a positive set with \a{name}.
Backreferences
A backreference ties parts of a string together: \1 repeats what the first group
(…) already generated.
<gen type="regex" value="([0-9]{3})-[A-Z]{2}-\1"/>
299-YZ-299 929-UE-929 462-VR-462 905-BC-905
The first and last three digits always match — that's the captured block. This is how you build document numbers in which one section repeats.
A reference may only point to a group that was already generated to its left; a forward reference is an error:
<gen type="regex" value="\1([0-9]{3})"/>
error: invalid regex generator pattern: backreference "\1" points to a group that is not generated yet
If the capture sits inside a repetition, the backreference uses the last value that group generated:
<gen type="regex" value="([A-Z]){3}-\1"/>
FZY-Y YHZ-Z LRG-G
Here ([A-Z]){3} runs the group three times, and \1 echoes only the third letter
it produced.
Named groups — (?<name>…)
A group can carry a name, and \k<name> repeats it. It is the same group \1 repeats —
a name is a second way to reach a group, not a second group:
<gen type="regex" value="(?<code>[A-Z]{2})-[0-9]{3}-\k<code>"/>
FZ-399-FZ YH-481-YH LR-586-LR YA-900-YA
A name makes a long pattern readable, and it is what a conditional reads. Three rules:
- A name starts with a letter or
_and holds letters, digits and_. - A name is used once. Two groups under one name would make
\k<name>a coin toss between them, settled by whichever the parser recorded last. \k<name>may only name a group that has already closed — the rule\1follows.
(?<=…) and (?<!…) are still lookbehind and still refused. Neither is a group whose
name begins with =.
Conditionals — (?(name)yes|no)
A conditional asks whether a group produced anything and writes one branch or the other. It is how you add a separator only when there is something to separate:
<gen type="regex" value="(?<area>0[1-9]{2})?(?(area)-|8 )[0-9]{4}"/>
099-9944 039-8189 063-8608 016-0097 8 7683 8 0194
The area code is optional. Where it appears a - follows it; where it does not, the row
starts 8 instead. Without a conditional that is two configs, or a <switch>.
- The conditional draws nothing. It reads a decision the group already made, so adding one to a pattern leaves every other value in the column exactly where it was.
- The second branch may be left out:
(?(area)-)writes the-or nothing at all. - A group can be tested by number too —
([0-9]{3})?(?(1)-). - Two branches, no more. A third is refused rather than quietly dropped; for a choice
inside a branch, group it:
(?(area)(?:x|y)|z).
A conditional may only test a group to its left, for the reason a backreference may only point to one — the group has produced nothing yet, so the branch could never be taken:
<gen type="regex" value="(?(area)-)(?<area>[0-9]{3})"/>
error: invalid regex generator pattern: conditional group "(?(area)...)" tests group "area", which is not generated yet
The length guard — regex_max_length
Every result is checked against
regex_max_length (default 32). A pattern that
could exceed it is rejected before generation:
<gen type="regex" value="[A-Z0-9]{40}"/>
error: invalid regex generator pattern: regex can produce 40 characters, which exceeds regex_max_length=32
Raise the cap for the whole config on <tdc>. Use this when a config has several
long patterns and you want one place to set the ceiling:
<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>
MURI40FXS16A2ABROOBQFGMSDBLWP3TCDTA16VVK NPJ3PVSU1NGARTRDQHT92IHGWJZVUST4531IOEAW 66WWVKTAA2XWUQJBJA8P0SNZ6W3Q75R3CP12JIXW
Or set it locally, on just this one generator, when a single field is the exception and you don't want to loosen the ceiling everywhere else:
<gen type="regex" value="[A-Z0-9]{40}" regex_max_length="40"/>
H88N88QPEO7XQU8Y3HSZVUVHBRNYDL22R5UYULFK 8J8P2G372CFQ09IGKO4DBWVJ7OX20A24XAGFOCA2 PXJS4YC5M13GUWUS7BVTYLT6Y3YFXOC04TLQUFZF
regex_max_length does not make an infinite regex finite — it only allows an
already-finite result to be longer.
What's not allowed
| Not allowed | Why | Use instead |
|---|---|---|
* | No upper bound | {0,n} |
+ | No upper bound | {1,n} |
{n,} | No upper bound | {n,m} |
Lazy *?, ?? | Matcher semantics, not generation | Write the range you want |
| Lookahead / lookbehind | Inspects existing text, doesn't build | Move the condition into the DSL |
\p{...} / \P{...} | Unicode properties aren't portable yet | \a{name} or an explicit class |
\n / \r | Multi-line generation lives elsewhere | Use separate <line>s |
For example, + is rejected immediately:
<gen type="regex" value="[a-z]+"/>
error: invalid regex generator pattern: unbounded "+" quantifier is not
allowed; use "{1,n}"Exact proportions
Plain regex doesn't set percentages inside the expression — (cat|dog) is random,
not "exactly 70/30". For exact shares, use:
<mix percent="…">to pick between DSL fragments<gen type="text" percent="…">for a set of valuesadvanced_regexfor weighted choice right inside the pattern
See also
- Advanced Regex — the same engine plus weighted choice.
- Symbol — when you only need a character set, not structure.
regex_max_lengthandalphabet.