Generates sample strings and test cases that a regex matches or rejects.
Part of PHPRegex, released with its siblings under one version number.
Documentation: php-regex.com — the API reference documents generate() end to end.
- Generates a random string the pattern matches, from the parsed AST, and checks it with the running engine
- Reproducible samples: seed the generator, reset the seed, draw again
- Open-ended quantifiers (
*,+,{n,}) capped by a configurable repetition limit - Unicode properties (
\p{Lu}), POSIX classes ([[:alpha:]]) and negated classes resolved by asking the running PCRE engine - Lookaheads and lookbehinds held where they stand; backreferences repeat what their group captured
- Matching and non-matching strings for a pattern, ready for a test suite
SampleGenerationExceptionwhen no sample can be built
composer require php-regex/regex-generatorRequires PHP 8.1+ and php-regex/regex-parser. MIT licensed.
maxRepetition(int, default3): extra repetitions drawn for*,+and{n,}seed(?int, defaultnull, last argument of theSampleGeneratorconstructor): locks the random source for reproducible samples; each sample drawn starts again from itsetSeed(int $seed)andresetSeed(): lock the random source later, or unlock itPcreEngine $engine(constructor of both generators): the engine asked what a class or a property holds
A sample the running engine matches: generate() draws from the pattern and checks each draw
with preg_match(), padding the sample when an assertion asks for text around it, and throws
SampleGenerationException when no draw matches:
use PHPRegex\Generator\SampleGenerator;
echo (new SampleGenerator())->generate('/(?!^)a/'); // "aa"A sample is at most 1,048,576 bytes, and so is every piece built on the way to it, a lookahead's
text and a padded candidate included: a pattern whose backreferences double the text at each
step, /(a)(\g{1}\g{1})(\g{2}\g{2})…/, throws SampleGenerationException ("No sample was
built: it would pass 1048576 bytes.") before the string is built. One candidate can go further:
a group fitted to substring scans, (*scs:…), joins a drawn prefix under the limit to its text for
each scan that reads it, and checks the candidate against the group and the scan before the sample
refuses it, so a group that two scans read can reach three times the limit.
A lookahead draws what follows it again, so lookaheads in a row nest: at most 128 deep, and at most
131,072 sequence entries copied for one sample. Past either, SampleGenerationException says which
limit was met. A plain repetition copies nothing and is not charged: /^(?:a.)+$/ repeated 37,329
times builds its 74,658-byte sample.
A repeat that adds text is bounded by the length of the sample; one that adds none, as a reference
to a group that captured nothing, is counted apart, 1,048,576 of them over the draws of one sample.
/()(?:\1{65535}){100}/, which PCRE compiles, throws SampleGenerationException ("No sample was
built: more than 1048576 repeats added nothing to it.") where it went through 6,553,500 repeats of
nothing; /a{65535}b{65535}/ builds its 131,070 bytes as before.
Visiting the tree draws from the tree alone, unchecked; a sample, made reproducible with a seed:
use PHPRegex\Generator\SampleGenerator;
use PHPRegex\Parser\RegexParser;
$generator = new SampleGenerator(seed: 42);
echo RegexParser::create()->parse('/[A-Z]{3}-\d{4}/')->accept($generator); // "VEL-0403"Test cases, matching and not, each one checked against the running engine (preg_match()
gives 1 on every matching case, 0 on every non-matching one):
use PHPRegex\Generator\TestCaseGenerator;
use PHPRegex\Parser\RegexParser;
$cases = RegexParser::create()->parse('/\d{3}-\d{4}/')->accept(new TestCaseGenerator());
echo $cases['matching'][0]; // "000-0000"
echo $cases['non_matching'][0]; // "00.000"When no sample can be built, the visitor says why:
use PHPRegex\Generator\Exception\SampleGenerationException;
use PHPRegex\Generator\SampleGenerator;
use PHPRegex\Parser\RegexParser;
try {
RegexParser::create()->parse('/(?&missing)/')->accept(new SampleGenerator());
} catch (SampleGenerationException $e) {
echo $e->getMessage(); // "Sample generation for subroutines is not supported."
}The Toolkit facade checks each sample against the running engine and retries before settling.
- Quick start — parse, generate and analyze in one tour
- API reference — the
generate()facade: retries, engine checks, error codes - Visitors — the visitor pattern both generators implement
- Testing and debugging — generated samples in a test workflow
- Backward compatibility — what stays stable across releases
- Upgrading from 1.x — moving from
yoeunes/regex-parser1.3 to 2.0, every change that needs one on your side - Changelog
- Bridges and tools — Laravel, Symfony, CLI, PHPStan and LSP
- Report issues and send pull requests in the main PHPRegex repository
If PHPRegex saves you time, consider sponsoring its maintenance.
MIT. See LICENSE.