re2
Safe, fast, thread-friendly regular expressions via Google's RE2 engine. Guarantees linear-time O(n) matching — no catastrophic backtracking, no ReDoS attacks.
Install
ppm install re2
What is RE2?
RE2 is a safe regular expression engine developed by Google. Unlike PCRE or the standard
std::regex, RE2 is built on finite automata (NFA/DFA)
and strictly avoids backtracking. This gives it a hard O(n) time guarantee on every input,
where n is the length of the text being searched.
The practical consequence: no matter how cleverly a pattern is crafted, RE2 will never hang. This makes it the correct choice for user-supplied patterns in production services — web forms, APIs, log processors, security tools — anywhere that a malicious or accidental ReDoS pattern could otherwise bring a server to its knees.
✓
Linear time O(n) — matching time is proportional to input length only, never to pattern complexity
✓
No ReDoS — immune to catastrophic backtracking attacks by design
✓
Thread-safe — compiled patterns can be shared across goroutines/threads without locking
✓
Full Unicode — UTF-8 by default, Unicode character classes (
\pL, \p{Greek}), POSIX classes
✓
Named capture groups —
(?P<name>...) syntax, accessible via GetNamedGroup
✓
Used by Go standard library (
regexp package), Chromium, Grafana, and Kubernetes
RE2 vs Other Engines
RE2
Time: O(n) — linear
ReDoS: impossible
Thread-safe: yes
Lookahead: no
Backref: no
PCRE2
Time: O(2^n) worst
ReDoS: possible
Thread-safe: w/ jit lock
Lookahead: yes
Backref: yes
std::regex
Time: O(2^n) worst
ReDoS: possible
Thread-safe: read-only ok
Lookahead: yes
Backref: yes
RE2 Limitations
RE2 does not support features that require backtracking:
lookahead
(?=...), lookbehind (?<=...),
negative variants, backreferences \1, possessive quantifiers a++,
or atomic groups (?>...).
If you need these features and trust your inputs, consider the regex package instead.
Types
| Type | Underlying | Description |
|---|---|---|
| TRE2Regex | Integer | Handle to a compiled RE2 pattern. Created by Compile / CompileEx. Must be freed with FreeRegex when done. |
| TRE2Options | record | Compilation flags passed to CompileEx. Fields: CaseInsensitive, Latin1, Longest, Literal, NeverNewline, DotNewline, MaxMemory. |
| TRE2Match | record | Result of a match operation. Contains Matched: Boolean, FullMatch: string, Start / Length (byte offsets), Groups: array of string (unnamed captures), and NamedGroups (Name/Value pairs). |
TRE2Options Fields
| Field | Description |
|---|---|
| CaseInsensitive | Case-insensitive matching, equivalent to inline flag (?i). |
| Latin1 | Treat input text as Latin-1 instead of UTF-8. |
| Longest | Prefer the longest match (POSIX leftmost-longest semantics). |
| Literal | Treat the entire pattern as a literal string, no metacharacters. |
| NeverNewline | . never matches \n (default behavior). |
| DotNewline | . matches \n as well (dot-all / single-line mode). |
| MaxMemory | Maximum DFA memory in bytes. Default 0 = 8 MB. Increase for complex patterns on very long inputs. |
API Reference
Compile / Free
function Compile(Pattern: string): TRE2Regex
Compile a RE2 pattern. Returns a handle. Check with
IsValid before use.function CompileEx(Pattern: string; Opts: TRE2Options): TRE2Regex
Compile with custom options (case-insensitive, dot-all, Latin-1, etc.).
procedure FreeRegex(R: TRE2Regex)
Free a compiled pattern. Must be called once per
Compile / CompileEx to avoid memory leaks.function IsValid(R: TRE2Regex): Boolean
Returns
True if the pattern compiled without errors.function GetError(R: TRE2Regex): string
Returns the compile error message when
IsValid is False.Match
function IsMatch(R: TRE2Regex; Text: string): Boolean
Returns
True if the pattern matches anywhere in Text. O(n) guaranteed. No groups returned.function Match(R: TRE2Regex; Text: string): TRE2Match
Find the first occurrence of the pattern anywhere in
Text. Returns match with capture groups.function FullMatch(R: TRE2Regex; Text: string): TRE2Match
Pattern must match the entire string. Equivalent to anchoring with
^...$.function PrefixMatch(R: TRE2Regex; Text: string): TRE2Match
Pattern must match at the start of the string. Equivalent to anchoring with
^....function MatchAll(R: TRE2Regex; Text: string): array of TRE2Match
Find all non-overlapping matches in
Text. Returns an array of match results, each with capture groups.function MatchAt(R: TRE2Regex; Text: string; Offset: Integer): TRE2Match
Find a match starting at a specific byte offset in
Text. Useful for iterative scanning.Named Groups
function GetNamedGroup(MR: TRE2Match; Name: string): string
Retrieve the value of a named capture group from a match result. Returns empty string if the group did not participate.
function NamedGroups(R: TRE2Regex): array of string
List all named group names defined in the compiled pattern, in left-to-right order.
function GroupCount(R: TRE2Regex): Integer
Returns the total number of capture groups (named + unnamed) in the pattern.
Replace
function Replace(R: TRE2Regex; Text, Rewrite: string): string
Replace the first match of the pattern in
Text. Rewrite may reference groups as \1, \2 or \{name}.function ReplaceAll(R: TRE2Regex; Text, Rewrite: string): string
Replace all non-overlapping matches. Same rewrite syntax as
Replace.Split
function Split(R: TRE2Regex; Text: string; Limit: Integer): array of string
Split
Text at every match of the pattern. Limit caps the number of parts; use 0 for unlimited.One-Shot Helpers
function QuickTest(Pattern, Text: string): Boolean
Compile and test in a single call. Convenient for one-off checks; avoid in loops (recompiles each call).
function QuickMatch(Pattern, Text: string): TRE2Match
Compile, match, and return result in one call. Pattern is freed internally after the match.
function QuickReplace(Pattern, Text, Rewrite: string): string
Compile, replace-all, and return result in one call.
Pattern Info
function MinMatchLength(R: TRE2Regex): Integer
Minimum length of a string that can match the pattern. Returns 0 if the pattern can match an empty string.
function CanMatchEmpty(R: TRE2Regex): Boolean
Returns
True if the pattern can match a zero-length string.function RE2Version(): string
Returns the version string of the underlying RE2 C library, e.g.
"2024-03-01".Code Example
uses re2;
var
R : TRE2Regex;
M : TRE2Match;
All : array of TRE2Match;
Opts: TRE2Options;
I : Integer;
begin
{ ── Compile a pattern with named groups ──────────────────── }
R := Compile('(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})');
if not IsValid(R) then
begin
WriteLn('Bad pattern: ', GetError(R));
Exit;
end;
{ ── Full match — pattern must cover the entire string ─────── }
M := FullMatch(R, '2024-03-15');
if M.Matched then
begin
WriteLn('Year : ', GetNamedGroup(M, 'year'));
WriteLn('Month : ', GetNamedGroup(M, 'month'));
WriteLn('Day : ', GetNamedGroup(M, 'day'));
end;
{ ── Find all dates in a sentence ─────────────────────────── }
All := MatchAll(R, 'dates: 2024-01-01 and 2024-12-31');
for I := 0 to Length(All) - 1 do
WriteLn('Found: ', All[I].FullMatch);
{ ── Replace with rewrite referencing named group ─────────── }
var Fixed := ReplaceAll(R,
'born 1990-06-21, hired 2015-03-01',
'\{day}/\{month}/\{year}');
WriteLn(Fixed); { "born 21/06/1990, hired 01/03/2015" }
{ ── Case-insensitive compile via options ──────────────────── }
Opts.CaseInsensitive := True;
var R2 := CompileEx('hello', Opts);
WriteLn(IsMatch(R2, 'Say HELLO world')); { True }
FreeRegex(R2);
{ ── Split on whitespace ──────────────────────────────────── }
var Parts := Split(Compile('\s+'), 'one two three', 0);
WriteLn(Parts[0], ' | ', Parts[1], ' | ', Parts[2]);
FreeRegex(R);
end.