Search by

php-regex / regex-explain

yoeunes

Explains, highlights and draws regex ASTs: plain text and HTML explanations, console and HTML highlighting, ASCII trees, Mermaid and railroad diagrams.

Package info

github.com/php-regex/regex-explain

Homepage

Issues

Documentation

pkg:composer/php-regex/regex-explain

Fund package maintenance!

yoeunes

Statistics

Installs: 11

Dependents: 4

Suggesters: 0

Stars: 0

2.x-dev 2026-11-09 16:06 UTC

This package is auto-updated.

Last update: 2026-11-09 16:43:56 UTC


README

PHPRegex Explain

Documentation Badge Author Badge GitHub Release Badge License Badge Packagist Downloads Badge GitHub Stars Badge Supported PHP Version Badge

PHPRegex Explain

Explains, highlights and draws regex ASTs: plain text and HTML explanations, console and HTML highlighting, ASCII trees, Mermaid and railroad diagrams.

Every class here is a node visitor: parse once with regex-parser, then walk the AST with accept(). There is nothing to configure.

Documentation: php-regex.com — the visitor reference is the class-by-class tour.

Features

  • Plain-English explanation, one line per construct (TextExplainer)
  • The same explanation as HTML, each node carrying a title tooltip (HtmlExplainer)
  • Terminal syntax highlighting in 24-bit ANSI colors (Highlighter\ConsoleHighlighter)
  • Web syntax highlighting as regex-token spans you style yourself (Highlighter\HtmlHighlighter)
  • ASCII tree of the AST, for logs and code review (AsciiTreeRenderer)
  • Mermaid flowchart source, for Markdown and docs sites (MermaidRenderer)
  • Standalone railroad-diagram SVG with its stylesheet embedded (RailroadSvgRenderer)
  • Covers the parser's whole PCRE node set: groups, quantifiers, class-set operations, conditionals, subroutines, callouts

Installation

composer require php-regex/regex-explain

Requires PHP 8.1+ and php-regex/regex-parser at the same version, pulled in automatically.

Usage

Explain a pattern in plain English:

use PHPRegex\Explain\TextExplainer;
use PHPRegex\Parser\RegexParser;

$ast = RegexParser::create()->parse('/[A-Z][a-z]+\d*/');

echo $ast->accept(new TextExplainer());
// Regex matches
//   Character Class: any character in [ Range: from 'A' to 'Z' ]
//   Character Class: any character in [ Range: from 'a' to 'z' ], one or more times
//   Character Type: A digit [0-9], zero or more times

A few readings moved across PCRE2 releases and locales: \w under u takes non-spacing marks from PCRE2 10.43, \w and \s without u follow the tables of the LC_CTYPE locale, and (?(VERSION>=10.5) reads its minor as two digits up to 10.46. Give the explainer the target the pattern is judged for, and each is explained as that engine reads it; without one, the explanation names the release or the locale the reading depends on. Regex::explain() passes the target of its instance.

use PHPRegex\Parser\PcreTarget;

$ast = RegexParser::create()->parse('/\w+/u');

echo $ast->accept(new TextExplainer(new PcreTarget(80300, '10.42')));
// Regex matches (with flags: u)
//   Character Type: A word character: a Unicode letter (\p{L}) or number (\p{N}), or an underscore, one or more times

Print the AST itself as a tree:

use PHPRegex\Explain\AsciiTreeRenderer;

$ast = RegexParser::create()->parse('/(?<year>\d{4})-\d{2}/');

echo $ast->accept(new AsciiTreeRenderer());
// Regex
// \-- Sequence
//     |-- Group (named) name="year"
//     |   \-- Quantifier ({4}, greedy)
//     |       \-- CharType (\d)
//     |-- Literal ('-')
//     \-- Quantifier ({2}, greedy)
//         \-- CharType (\d)

Both write the text a pattern carries, a comment, a callout string or the name of a verb such as (*MARK:…), in display form: a control character is written \xHH (\x1B), a line break, a tab or a carriage return \n, \t or \r, and a character that moves or hides text such as U+202E \x{202E}. An explanation keeps one line per construct, and the escape sequences of a pattern never reach the terminal.

Both stop at 8 MiB of output, indentation and line breaks counted: a pattern of a few dozen kilobytes can nest a long run deep enough to need far more, and rendering it throws a ResourceLimitException whose errorCode is ErrorCode::RenderingOutputTooLarge (regex.rendering.output_too_large) instead of exhausting memory. The visitor can be reused after it threw.

Highlight the pattern instead of explaining it — ANSI for a terminal, span classes for a web page:

use PHPRegex\Explain\Highlighter\ConsoleHighlighter;
use PHPRegex\Explain\Highlighter\HtmlHighlighter;

$ast = RegexParser::create()->parse('/\d{2,}/');

// wraps each token as \e[38;2;R;G;Bm...\e[0m (true color)
echo $ast->accept(new ConsoleHighlighter());

echo $ast->accept(new HtmlHighlighter());
// <span class="regex-token regex-type regex-escape">\d</span><span class="regex-token regex-quantifier">{2,}</span>

Render an explanation ready for a web page — the title attribute holds the detail:

use PHPRegex\Explain\HtmlExplainer;

echo RegexParser::create()->parse('/\d{3}-\d{4}/')->accept(new HtmlExplainer());
// <div class="regex-explain">
// <strong>Regex matches:</strong>
// <ul><li><span title="Character Type: A digit [0-9], exactly 3 times">Character Type: <strong>\d</strong> (A digit [0-9])</span>, exactly 3 times</li>…
// </ul>
// </div>

Draw the pattern — Mermaid source for a docs page, a complete SVG for anywhere else:

use PHPRegex\Explain\MermaidRenderer;
use PHPRegex\Explain\RailroadSvgRenderer;

$ast = RegexParser::create()->parse('/a(b|c)*/');

echo $ast->accept(new MermaidRenderer());
// graph TD;
//     node0["Regex: none"]
//     node1["Sequence"]
//     node2["Literal: a"]
//     node1 --> node2
//     node3["Quantifier: *"]
//     … remaining nodes and edges …

file_put_contents('railroad.svg', $ast->accept(new RailroadSvgRenderer()));
// a complete XML document: an <svg> root with its stylesheet embedded

Documentation

Resources

Sponsors

Sponsor

If PHPRegex saves you time, consider sponsoring its maintenance.

License

MIT. See LICENSE.