Regular Expressions

The Regular Expression Interface

Creating an Expression

RegEx::compile accepts owning UTF-8, UTF-16 and UTF-32 Core strings. Every overload returns RegExPtr and produces equivalent compiled behaviour.

using namespace erbsland::text::literals;

const auto expression8 = re::RegEx::compile("(A)(πŸ˜€)(B)"_el);
const auto expression16 = re::RegEx::compile(text::U16String{u"(A)(πŸ˜€)(B)"_el});
const auto expression32 = re::RegEx::compile(text::U32String{U"(A)(πŸ˜€)(B)"_el});

Invalid syntax and configured limits throw RegExError. Pattern length is measured in decoded code points, independently of the source encoding. The compiled object retains the normalized UTF-8 source text returned by pattern(). UTF-16 and UTF-32 patterns therefore produce the same stored representation as an equivalent UTF-8 pattern.

Lazy Compilation

RegEx::lazyCompile retains the pattern, flags and settings without parsing the pattern immediately. The first matching, replacement or diagnostic operation compiles the engine. Copies of a lazy expression share this state, and concurrent first use compiles one engine for all copies.

Use isCompiled() to inspect the state without triggering compilation. Use compileNow() when an application needs to validate a lazy pattern before matching. Invalid lazy patterns throw RegExError at that point. A failed attempt leaves the expression uncompiled, and a later operation retries compilation.

Matching Operations

Each supported string width provides the same five operations:

  • match starts at the beginning of the subject.

  • fullMatch requires the complete subject to match.

  • findFirst searches for the first match.

  • findAll lazily yields matches from a coroutine generator.

  • collectAll eagerly returns all matches in a std::vector.

match, fullMatch and findFirst return nullptr when no match exists. The generator and list operations return an empty result.

Subjects and Results

The subject parameter determines the result family:

Core strings own their backing storage. Inputs, returned matches and lazy generators therefore remain valid after the caller’s original string or temporary has been destroyed.

Tolerant String Decoding

All Core-string entry points decode malformed source units as U+FFFD. This applies to patterns, UTF-8/16/32 subjects, assembler source and replacement expressions. Replacement characters participate in parsing and matching like any other character, including CRLF lookahead and zero-width advancement paths.

Custom input implementations control their own decoding policy and may throw encoding or other runtime errors. Such exceptions propagate unchanged.

Text Streams

The matching operations also accept stream::TextInputStreamPtr. The stream must support positioning because the matching engine stores only byte ranges for capture groups. After a successful match, the API seeks to each captured range and copies its text into the returned Match object. The returned match therefore remains valid after the stream has been reused or destroyed.

Capture copying restores the stream’s logical position before the next matching operation continues. Streams that do not support positioning cause err::ParameterError. Read or positioning timeouts cause stream::StreamError and are never treated as end-of-input.

Null Characters

By default, regular expression patterns reject U+0000, including raw pattern text and character escapes. Enable Feature::AcceptNullInPattern only when a pattern needs to match a null character.

Matching input accepts U+0000 by default and processes all following input normally. To reject U+0000 at the point it is read, disable Feature::AcceptNullInInput; matching then throws text::EncodingError.

Replacement

replaceAll accepts either a replacement expression or a callback receiving MatchPtr. The callback returns an owning text::String, allowing it to reuse unchanged input or match content without creating an intermediate string copy. Use text::U8String::toEscaped with text::EscapeFormat::RegEx to escape text for insertion as a literal pattern.

Settings

The Settings class allows you to control which features are accepted and which limits apply when compiling and executing regular expressions.

Settings are applied during compilation and define the behaviour of the resulting RegEx instance. They are especially important when your application processes patterns from external or untrusted sources, such as user configuration files or plug-in systems.

Limiting the Run-Time

When working with externally provided patterns, it is strongly recommended to limit the maximum run-time of matching operations.

Using setTimeout, you can define a per-call time limit for all matching operations performed by a RegEx instance.

If a matching operation exceeds the configured timeout, it is aborted and an RegExError exception with the error category Timeout is thrown.

This mechanism protects your application against excessively complex patterns or pathological input that would otherwise lead to long or unbounded execution times.

Setting Pattern Complexity Limits

In addition to time limits, the library provides a set of limits that restrict individual aspects of pattern complexity, such as nesting depth, repetition counts, or internal resource usage.

These limits can only be tightened, never extended. The library ships with a carefully chosen set of safe default limits that work well for most use cases.

Reducing these limits is useful when you want to:

  • Prevent excessive memory consumption

  • Guard against denial-of-service scenarios

  • Enforce predictable performance characteristics

All limits are checked during compilation or execution and result in a well-defined error if exceeded.

Enabling or Disabling Features

By default, the regular expression support in Erbsland Core enables a number of compatibility features to ease migration from existing regular expression engines.

While convenient, some of these features come with ambiguities, surprising edge cases, or performance costs. For applications that accept patterns from external sources, it is often desirable to restrict the accepted syntax more strictly.

The feature flags in Settings allow you to explicitly control which parts of the pattern syntax are enabled.

A sensible starting point for untrusted patterns is disabling AllCompatibility, thereby accepting only the core, well-defined syntax.

Certain particularly problematic features are disabled by default:

  • EmptyAlternatives

  • EmptyGroups

Both can lead to unintuitive matches and make patterns harder to reason about. If you enable them, you should do so consciously and only when their behaviour is clearly understood and required.

Choosing the Right Settings

For internal, fully controlled patterns, the default settings are usually sufficient and provide maximum convenience.

For externally supplied patterns, we recommend:

  • Enabling a strict timeout

  • Tightening complexity limits where possible

  • Disabling compatibility features that are not explicitly required

This layered approach keeps your application robust while still allowing powerful and expressive regular expressions.

The Input Interface

The Input interface allows you to provide custom input sources to the regular expression engine.

Because the regular expression engine in Erbsland Core is based on a Thompson NFA, input is consumed sequentially and processed in a highly efficient streaming fashion. This makes it possible to match patterns not only against built-in Core strings, but also against custom iterators or application-specific sources.

The input interface is a low-level extension point intended for advanced use cases. If you only need to match against strings, the built-in string overloads are usually the better and simpler choice. They also provide a defined tolerant decoding policy: malformed units are replaced with U+FFFD.

How to Implement Your Source

To implement a custom input source, derive from one of the following classes:

The chosen base class determines which unified match family is returned: Match, Match16 or Match32. A custom input implements createMatch and decides whether captured content is copied or retained as a slice of its source.

Your implementation must override the abstract methods defined by InputBase. These methods form the contract between your input source and the matching engine.

Implementation Requirements

The most important method is read. It is invoked in the hot loop of the matching engine and must therefore be implemented as efficiently as possible.

When implementing an input source, the following rules must be respected:

  • read must return the next character as text::Char together with its position. Every returned character must be a valid Unicode scalar value.

  • When the end of the input is reached, text::Char::endOfData must be returned.

  • Repeated calls to read after the end of the input must continue to succeed and keep returning the end-of-data signal.

  • Reserved text::Char signals other than the end-of-data signal, surrogate code points and values above U+10FFFF must never be returned.

  • The returned position must advance monotonically and must uniquely identify the character within the input stream.

If line-break folding (CRLF handling) is enabled for the regular expression, your input source must additionally implement:

These methods allow the engine to treat CRLF sequences as a single logical line break while preserving correct positional information.

The matching engine relies on this contract and does not repeat Unicode validity checks in its hot loop. Validate or decode custom data before returning it. Error-tolerant inputs should replace invalid source values with text::Char::replacement. Incorrect or incomplete implementations may lead to incorrect matches or undefined behavior.

Exception Propagation

A custom input may choose strict decoding and throw a Core encoding error. Exceptions thrown by read(), peek(), skip() or createMatch() propagate unchanged through every matching operation. The engine does not replace, wrap or translate these exceptions into RegExError.

Example Implementation

The following example shows a complete implementation of a custom input source that reads characters from a std::vector. While simplified, it demonstrates all required methods and lifetime rules. The example treats the vector as an error-tolerant source and replaces invalid UTF-32 values while reading and capturing its content.

 1#pragma once
 2
 3#include <erbsland/Char.hpp>
 4#include <erbsland/re/Input.hpp>
 5#include <erbsland/re/Match.hpp>
 6#include <erbsland/text/u32/U32String.hpp>
 7
 8#include <string>
 9#include <utility>
10#include <vector>
11
12// FIXME!
13// This should be moved into a demo - to make sure it compiles and works as expected.
14// This demo also makes no sense with Erbsland Core, it needs to adapted to use the correct types.
15
16class VectorMatch : public erbsland::re::Match32 {
17public:
18    using Match32::Match32;
19
20public:
21    VectorMatch(el::re::CaptureGroupList captureGroupList, std::u32string &&capturedContent, const std::size_t offset) :
22        Match32(std::move(captureGroupList)), _capturedContent{std::move(capturedContent)}, _offset{offset} {}
23    ~VectorMatch() override = default;
24
25protected:
26    [[nodiscard]] auto getContentForGroup(const el::re::CaptureGroup &group) const noexcept
27        -> el::text::U32String override {
28
29        return el::text::U32StringEditor{_capturedContent}.slice({group.begin() - _offset, group.size()});
30    }
31
32private:
33    std::u32string _capturedContent;
34    std::size_t _offset;
35};
36
37class VectorInput : public erbsland::re::Input32 {
38public:
39    explicit VectorInput(const std::vector<char32_t> &textVector) : _vectorRef(textVector) {}
40    ~VectorInput() override = default;
41
42public:
43    [[nodiscard]] auto read() -> el::re::CharAndPosition override {
44        if (_position >= _vectorRef.size()) {
45            return {el::text::Char::endOfData(), _position};
46        }
47        const auto position = _position;
48        const auto character = decodeCodePoint(_vectorRef[position]);
49        _position += 1;
50        return {character, position};
51    }
52    [[nodiscard]] auto peek() -> el::re::CharAndPosition override {
53        if (_position >= _vectorRef.size()) {
54            return {el::text::Char::endOfData(), _position};
55        }
56        return {decodeCodePoint(_vectorRef[_position]), _position};
57    }
58    void skip(const std::size_t characterCount) override {
59        _position += characterCount;
60        if (_position > _vectorRef.size()) {
61            _position = _vectorRef.size();
62        }
63    }
64    [[nodiscard]] auto createMatch(el::re::CaptureGroupList captureGroupList) -> el::re::Match32Ptr override {
65
66        std::u32string capturedContent;
67        const std::size_t offset = captureGroupList.front().begin();
68        const std::size_t end = captureGroupList.front().end();
69        for (std::size_t i = offset; i < end; ++i) {
70            capturedContent.push_back(decodeCodePoint(_vectorRef.at(i)).toRawValue());
71        }
72        return std::make_shared<VectorMatch>(std::move(captureGroupList), std::move(capturedContent), offset);
73    }
74
75private:
76    [[nodiscard]] static auto decodeCodePoint(const char32_t codePoint) noexcept -> el::text::Char {
77        const auto character = el::text::Char{codePoint};
78        return character.isValidUnicode() ? character : el::text::Char::replacement();
79    }
80
81    const std::vector<char32_t> &_vectorRef;
82    std::size_t _position = 0;
83};

The Match Interface

Match Families

A successful match is represented by one encoding-specific type:

There is no separate view-result family. Core strings are read-only owning values, so matches retain their subject storage and return copy-free slices from it.

Lifetime and Ownership

Match objects are shared pointers and are immutable after creation. The match keeps the complete subject string alive; every value returned by content() also owns the referenced storage. It is safe to retain a match or captured string after the source variable, temporary subject or generator has been destroyed.

Groups and Positions

MatchBase provides begin, end, range and group access. Overloads without a selector address capture group zero, which represents the whole match. Other groups are selected with CaptureGroupIndex or a text::String name.

Positions are coordinates in the original encoding:

  • UTF-8 positions count bytes.

  • UTF-16 positions count char16_t code units, including both units of a surrogate pair.

  • UTF-32 positions count char32_t code units.

end() identifies the first unit after the captured range. content() converts the stored coordinates into a native Core string slice without copying.

Regular Expression Errors

Regular-expression parsing, diagnostics and execution failures are reported with RegExError. The exception derives from err::RuntimeError and carries a RegExErrorContext.

try {
    const auto expression = re::RegEx::compile(pattern);
} catch (const re::RegExError &error) {
    log(error.diagnostic()->toString());
}

Error Context

The context separates information that applications commonly need to inspect:

  • title is a concise statement of what failed. The inherited reason() and what() contain only this title.

  • description optionally explains why the operation failed, including limits or relevant values.

  • category identifies the subsystem or failure kind without duplicating it in the title.

  • location stores optional, zero-based typed line, column and code-point indices.

The corresponding convenience accessors are available directly on RegExError. Missing location components return the respective noIndex value. withLineNumber() returns a copy with a replaced zero-based line index and preserves every other context field.

Every RE subsystem follows the same message split. The title states which operation failed, such as Failed to parse regular expression or Failed to assemble regular expression. The description states the concrete cause, including relevant values and limits. Category and location are never duplicated in either text field.

Diagnostics

diagnostic() returns a structured Core diagnostic whose toString() method renders the complete plain-text diagnostic, including the title, optional description, category and every available location component. Human-readable locations are rendered one-based, while the inspection API remains zero-based. RegExError::toString() provides a compact single-line summary in the form <category>: <title>. <description> and deliberately omits structured location details.

Core Strings and Encoding

Every RE API that receives a Core string uses tolerant decoding. Malformed UTF-8, UTF-16 or UTF-32 units become U+FFFD and participate normally in pattern parsing, assembler parsing, replacement parsing and matching. These string overloads therefore do not throw encoding errors for malformed units.

Custom input implementations remain exception-transparent. An encoding error or another runtime error thrown by read(), peek(), skip() or createMatch() propagates unchanged and is not converted into RegExError.

Categories

Parser and Format identify invalid pattern and replacement syntax. Assembler identifies invalid diagnostic program text. Limit and Timeout identify configured resource boundaries. Engine and Internal identify execution or invariant failures.

Diagnostics

The regular expression support in Erbsland Core includes a low-level assembler and disassembler that allow you to inspect, analyze, and even manually construct the internal program executed by the matching engine.

These tools are primarily intended for diagnostics, debugging, testing, and advanced experimentation. They are not required for normal use of the library, but they provide valuable insight into how patterns are translated into executable instructions.

Disassemble Compiled Patterns

The disassembler can be used to inspect the program generated by the compiler for a given regular expression pattern.

const auto reTag = RegEx::compile(R"((?is)<([a-z]+)([^>]*)>)");

for (const auto &line : diagnostics::Disassembler{reTag}.disassemble()) {
    std::cout << line << '\n';
}

This produces a textual representation of the compiled program, including character classes, control flow, and capture group handling:

; Character classes
; ============================================================================
.section &class
$0000:                                  .class              ; [a-z]
$0000:                                  .data $000061-$00007A
; Program
; ============================================================================
.section &program
$0000:            0900003c              CI CHAR '<'
$0001:            86000000              START CAPTURE 0
$0002:            0c000000              CI CLASS $0000
$0003:            81000002 00000005     SPLIT $0002, $0005
$0005:            a6000000              STOP CAPTURE 0
$0006:            86000001              START CAPTURE 1
$0007:            81000009 0000000b     SPLIT $0009, $000B
$0009:            2900003e              NOT CI CHAR '>'
$000A:            c2000007              JUMP $0007
$000B:            a6000001              STOP CAPTURE 1
$000C:            0900003e              CI CHAR '>'
$000D:            83000000              MATCH

Reading this output is helpful when:

  • debugging unexpected matching behaviour,

  • analyzing performance characteristics,

  • learning how specific pattern constructs are compiled.

Write Custom Programs

For advanced use cases, you can also write custom matching programs directly using the assembler.

This allows you to bypass the regular expression syntax entirely and construct a program manually using the engine’s instruction set.

using namespace erbsland::text::literals;
const auto program = text::StringList{
    "; my custom program"_el,
    "loop: CHAR 'a'"_el,
    "      SPLIT %loop, %end"_el,
    "end:  MATCH"_el,
};

auto reCustom = diagnostics::Assembler().compile(program);
auto match = reCustom->match("aaaaaa"_el);

std::cout << "Result: " << match->content() << '\n';
Result: aaaaaa

Custom programs are useful for testing the engine, experimenting with new instruction sequences, or creating minimal reproducible examples when investigating bugs.

The assembler accepts text::StringList. The disassembler returns the same owning Core list type, so listings remain valid independently of the disassembler object. Assembler source uses tolerant Core-string decoding. Malformed UTF-8 units become U+FFFD before tokenization. Syntax and limit failures are reported as RegExError with an Assembler category and a zero-based structured source location; the rendered diagnostic presents locations one-based.

Interface

class CaptureGroup

The definition of a match group.

Public Functions

constexpr CaptureGroup() noexcept = default

Create an empty capture group.

inline constexpr CaptureGroup(const CaptureGroupIndex index, const CaptureRange range, const text::String &name) noexcept

Create a new match group with the given capture range, and name.

Parameters:
  • index – The index of the group. 0 = complete match, 1 = first capture group.

  • range – The character range for the group.

  • name – The name of the group.

inline constexpr CaptureGroupIndex index() const noexcept

Get the index of this capture group.

inline constexpr bool isEmpty() const noexcept

Test if the group is empty.

Returns:

True if begin equals end, false otherwise.

inline constexpr std::size_t size() const noexcept

Get the size of the group.

Returns:

The number of positions between begin and end.

inline constexpr InputPosition begin() const noexcept

Get the start position for the match.

Returns:

The begin position (inclusive).

inline constexpr InputPosition end() const noexcept

Get the end position for the match.

Returns:

The end position (exclusive).

inline constexpr CaptureRange range() const noexcept

Get the range of for the match.

Returns:

The range.

inline constexpr text::String name() const noexcept

Get the name of the match group.

inline void setIndex(const CaptureGroupIndex index) noexcept

Set the index for the group.

Parameters:

index – The group index.

inline void setBegin(const InputPosition begin) noexcept

Set the start position for the match.

Parameters:

begin – The begin position (inclusive).

inline void setEnd(const InputPosition end) noexcept

Set the end position for the match.

Parameters:

end – The end position (exclusive).

inline void setName(const text::String &name) noexcept

Set the name of the match group.

Parameters:

name – The name of the group.

using erbsland::re::CaptureGroupList = std::vector<CaptureGroup>

A list of capture groups.

using erbsland::re::CaptureGroupIndex = uint16_t

The index of a capture group.

Group index 0 is the full match, 1 is the first capture group, etc.

class CaptureRange

Represents a range in the input, defined by begin and end positions.

This class is used to represent captured content ranges in regular expression matches. The range is defined as [begin, end], where begin is inclusive and end is exclusive.

Public Functions

inline constexpr CaptureRange(const InputPosition begin, const InputPosition end) noexcept

Create a new capture range with the given begin and end positions.

Parameters:
  • begin – The start position of the range (inclusive).

  • end – The end position of the range (exclusive).

inline constexpr bool isEmpty() const noexcept

Test if the range is empty.

Returns:

True if begin equals end, false otherwise.

inline constexpr std::size_t size() const noexcept

Get the size of the range.

Returns:

The number of positions between begin and end.

inline constexpr InputPosition begin() const noexcept

Get the start position of the range.

Returns:

The begin position (inclusive).

inline constexpr InputPosition end() const noexcept

Get the end position of the range.

Returns:

The end position (exclusive).

inline void setBegin(const InputPosition begin) noexcept

Set the start position of the range.

Parameters:

begin – The new begin position (inclusive).

inline void setEnd(const InputPosition end) noexcept

Set the end position of the range.

Parameters:

end – The new end position (exclusive).

inline text::String toString() const

Convert the range into a short, human-readable string.

Returns:

The formatted range as "begin-end".

struct CharAndPosition

A read character and its start position.

Public Members

text::Char character

The read character or the end-of-data signal.

InputPosition position

The start position of the read character.

class Assembler

An assembler for diagnostics, unit test, and experiments.

Please read the documentation for the full syntax of the assembler language.

Public Functions

RegExPtr compile(const text::StringList &lines) const

Compile the given assembler program into a regular expression object.

Parameters:

lines – The lines of the assembler code to compile.

Throws:

RegExError – on any compilation error.

Returns:

The compiled regular expression object.

class Disassembler

A disassembler for the regular expression engine data.

Public Functions

explicit Disassembler(const ConstRegExPtr &regEx)

Create a new instance for the given regular expression.

text::StringList disassemble() const

Disassemble the engine data into human-readable instructions.

enum class erbsland::re::ErrorCategory : uint8_t

The category of an RegExError.

Values:

enumerator Parser

A parser error.

enumerator Format

A format error in a replacement string.

enumerator Assembler

An assembler error.

enumerator Engine

An engine error.

enumerator Timeout

A timeout error.

enumerator Limit

A limit error.

enumerator Internal

An internal error.

inline text::String erbsland::re::toString(const ErrorCategory category) noexcept

Convert an error category into a stable, human-readable name.

enum class erbsland::re::Feature : uint16_t

A feature of the regular expression syntax or engine.

Values:

enumerator QuotedLiterals

Using quotes \\Q...\\E.

enumerator EscapeBell

The escape sequence \\a for bell character.

enumerator EscapeControl

The escape sequence \\cX for control character.

enumerator EscapeEscape

The escape sequence \\e for the escape character.

enumerator EscapeFormFeed

The escape sequence \\f for form feed character.

enumerator EscapeOctal

The escape sequence \\o{nnn} for octal character.

enumerator EscapeHex

The escape sequence \\xnn and \\x{nnnn} for hexadecimal character.

enumerator EscapeLongUnicode

The escape sequence \\Unnnnnnnn for 32-bit Unicode character.

enumerator EscapeHorizontalSpace

The escape sequence \\h for horizontal space character.

enumerator EscapeVerticalSpace

The escape sequence \\v for vertical space character.

enumerator PosixClasses

Using POSIX character classes like [:digit:]

enumerator AnchorLowercaseZ

Using the anchor \\z for the end of the string.

enumerator EmptyAlternatives

Allow empty alternatives, like (?:a|b|)

enumerator EmptyGroups

Allow empty groups, like ()

enumerator AcceptNullInPattern

Allow null characters in regular expression patterns.

enumerator AcceptNullInInput

Allow null characters in matching input.

enumerator AllCompatibility

All compatibility options.

enumerator Default

The default value (enable all compatibility features and null characters in input)

inline text::String erbsland::re::toString(const Feature feature)

Convert a feature to a string representation.

class Features : public erbsland::util::EnumFlags<Feature, Features>

Features for compiling regular expressions.

Public Functions

inline text::String toString() const

Create a diagnostic string for the enabled features.

Public Static Functions

static inline constexpr std::array<Feature, 16> all() noexcept

Get every supported regular-expression feature in stable order.

enum class erbsland::re::Flag : uint8_t

A single flag.

Values:

enumerator None
enumerator IgnoreCase

Ignore case when matching text.

enumerator Multiline

Match at the beginning and end of each line.

enumerator DotAll

The dot operator also matches newlines.

enumerator Ascii

Restrict \\w, \\d, \\s to ASCII only matching.

enumerator Verbose

Ignore spacing in the regular expression.

enumerator CRLF

Interpret CRLF line endings like a single LF.

Both characters of such line-endings are preserved when capturing text.
This works similar to the folding of multi-code point Unicode characters.
E.g. ``a¨`` is interpreted as ``À``, but both code-points are preserved in text.
inline text::String erbsland::re::toString(const Flag flag)

Convert a flag to a string representation.

class Flags : public erbsland::util::EnumFlags<Flag, Flags>

Flags for constructing a regular expression object.

Public Functions

inline text::String toString() const

Create a diagnostic string for the flags.

Public Static Functions

static inline constexpr std::array<Flag, 6> all() noexcept

Get every supported regular-expression flag in stable order.

class Input : public erbsland::re::InputBase

An abstract input for regular expression matching.

Subclassed by erbsland::re::impl::StreamInput, erbsland::re::impl::StringInput

Public Functions

virtual MatchPtr createMatch(CaptureGroupList captureGroupList) = 0

Create a match object for this input.

Parameters:

captureGroupList – The list of capture groups.

Returns:

An owning match result that holds a copy of the matched text. Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

using erbsland::re::InputPtr = std::shared_ptr<Input>

A shared pointer to an input instance.

class Input16 : public erbsland::re::InputBase

An abstract UTF-16 input for regular expression matching.

Subclassed by erbsland::re::impl::U16StringInput

Public Functions

virtual Match16Ptr createMatch(CaptureGroupList captureGroupList) = 0

Create a match object for this input.

Parameters:

captureGroupList – The list of capture groups.

Returns:

An owning match result that holds a copy of the matched text. Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

using erbsland::re::Input16Ptr = std::shared_ptr<Input16>

A shared pointer to a UTF-16 input instance.

class Input32 : public erbsland::re::InputBase

An abstract UTF-32 input for regular expression matching.

Subclassed by erbsland::re::impl::U32StringInput

Public Functions

virtual Match32Ptr createMatch(CaptureGroupList captureGroupList) = 0

Create a match object for this input.

Parameters:

captureGroupList – The list of capture groups.

Returns:

An owning match result that holds a copy of the matched text. Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

using erbsland::re::Input32Ptr = std::shared_ptr<Input32>

A shared pointer to a UTF-32 input instance.

class InputBase : public std::enable_shared_from_this<InputBase>

The abstract base class for inputs for regular expression matching.

Exceptions raised by input operations propagate unchanged through the matching engine.

Subclassed by erbsland::re::Input, erbsland::re::Input16, erbsland::re::Input32, erbsland::re::impl::NullRejectingInput

Public Functions

virtual CharAndPosition read() = 0

Read the next character from the input and advance the position.

Implementations must return a valid Unicode scalar value, or text::Char::endOfData() after exhaustion. Repeated reads after exhaustion must keep returning the end-of-data signal. Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

Returns:

1. The next character from the input, or the end-of-data signal after exhaustion.

  1. The start position of the read character (the position of the first byte of the read character).

virtual CharAndPosition peek() = 0

Peek at the next character from the input, do not advance the position.

Implementations must follow the same valid-scalar/end-of-data contract as read(). Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

Returns:

1. The next character from the input, or the end-of-data signal after exhaustion.

  1. The start position of the read character (the position of the first byte of the read character).

virtual void skip(unit::CpLength characterCount) = 0

Skip a number of characters.

Skipping beyond the available input must leave the input exhausted. Implementations may throw encoding errors or other runtime errors; matching operations propagate them unchanged.

using erbsland::re::InputBasePtr = std::shared_ptr<InputBase>

A shared pointer to an input instance.

using erbsland::re::InputPosition = std::size_t

A position in the input stream.

This is a valid position in the input. The concrete meaning depends on the used Input implementation.

  • UTF8 => the position of the start byte (char, char8_t) for a character.

  • UTF16 => the position of the start word (char16_t) for a character.

  • UTF32 => the position of the character (char32_t).

class Match : public erbsland::re::MatchBase

An owning match result.

The returned views from content() are valid for the lifetime of this object.

Subclassed by erbsland::re::impl::StreamMatch, erbsland::re::impl::StringMatch

Public Functions

text::String content() const

Get the full content of the match.

text::String content(CaptureGroupIndex groupIndex) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group index is invalid.

text::String content(const text::String &groupName) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group name is invalid.

using erbsland::re::MatchPtr = std::shared_ptr<Match>

A shared pointer to a match result.

using erbsland::re::MatchGenerator = util::CoGenerator<MatchPtr>

A generator returning matches.

using erbsland::re::MatchList = std::vector<MatchPtr>

A list of matches.

class Match16 : public erbsland::re::MatchBase

An owning UTF-16 match result.

The returned views from content() are valid for the lifetime of this object.

Subclassed by erbsland::re::impl::U16StringMatch

Public Functions

text::U16String content() const

Get the full content of the match.

text::U16String content(CaptureGroupIndex groupIndex) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group index is invalid.

text::U16String content(const text::String &groupName) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group name is invalid.

using erbsland::re::Match16Ptr = std::shared_ptr<Match16>

A shared pointer to a UTF-16 match result.

using erbsland::re::Match16Generator = util::CoGenerator<Match16Ptr>

A generator returning UTF-16 matches.

using erbsland::re::Match16List = std::vector<Match16Ptr>

A list of UTF-16 matches.

class Match32 : public erbsland::re::MatchBase

An owning UTF-32 match result.

The returned views from content() are valid for the lifetime of this object.

Subclassed by erbsland::re::impl::U32StringMatch

Public Functions

text::U32String content() const

Get the full content of the match.

text::U32String content(CaptureGroupIndex groupIndex) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group index is invalid.

text::U32String content(const text::String &groupName) const

Get the content of the specified group.

Throws:

err::ParameterError – if the group name is invalid.

using erbsland::re::Match32Ptr = std::shared_ptr<Match32>

A shared pointer to a UTF-32 match result.

using erbsland::re::Match32Generator = util::CoGenerator<Match32Ptr>

A generator returning UTF-32 matches.

using erbsland::re::Match32List = std::vector<Match32Ptr>

A list of UTF-32 matches.

class MatchBase

The abstract baseclass for regular expression matches.

Subclassed by erbsland::re::Match, erbsland::re::Match16, erbsland::re::Match32

Public Functions

virtual InputPosition begin() const

Get the start position of the match.

virtual InputPosition begin(CaptureGroupIndex groupIndex) const

Get the start position of the given group.

Parameters:

groupIndex – The index of the group.

Throws:

err::ParameterError – if the group index is invalid.

virtual InputPosition begin(const text::String &groupName) const

Get the start position of the given group.

Parameters:

groupName – The name of the group.

Throws:

err::ParameterError – if the group name is invalid.

virtual InputPosition end() const

Get the end position of the match.

The end position points after the last character of the match.

virtual InputPosition end(CaptureGroupIndex groupIndex) const

Get the end position of the given group.

The end position points after the last character of the match.

Parameters:

groupIndex – The index of the group.

Throws:

err::ParameterError – if the group index is invalid.

virtual InputPosition end(const text::String &groupName) const

Get the end position of the given group.

The end position points after the last character of the match.

Parameters:

groupName – The name of the group.

Throws:

err::ParameterError – if the group name is invalid.

virtual CaptureRange range() const

Get the range of the match.

The range is defined as [begin, end] where begin is inclusive and end is exclusive.

virtual CaptureRange range(CaptureGroupIndex groupIndex) const

Get the range of the given group.

The range is defined as [begin, end] where begin is inclusive and end is exclusive.

Parameters:

groupIndex – The index of the group.

Throws:

err::ParameterError – if the group index is invalid.

virtual CaptureRange range(const text::String &groupName) const

Get the range of the given group.

The range is defined as [begin, end] where begin is inclusive and end is exclusive.

Parameters:

groupName – The group name.

Throws:

err::ParameterError – if the group name is invalid.

virtual const CaptureGroup &group() const

Get the capture group of the match.

Returns:

A reference to the capture group instance.

virtual const CaptureGroup &group(CaptureGroupIndex groupIndex) const

Get the capture group of the given group.

Parameters:

groupIndex – The index of the group.

Throws:

err::ParameterError – if the group index is invalid.

Returns:

A reference to the capture group instance.

virtual const CaptureGroup &group(const text::String &groupName) const

Get the capture group of the given group.

Parameters:

groupName – The name of the group.

Throws:

err::ParameterError – if the group name is invalid.

Returns:

A reference to the capture group instance.

virtual std::size_t groupCount() const noexcept

Get the number of capture groups, including the full match.

If there are two capture groups (a)(b), this function will return 3, as the full match counts as capture group zero ((a)(b)).

virtual bool hasGroupIndex(CaptureGroupIndex groupIndex) const noexcept

Test if the given group index exists.

virtual bool hasGroupName(const text::String &groupName) const noexcept

Test if the given group name exists.

using erbsland::re::MatchBasePtr = std::shared_ptr<MatchBase>

A shared pointer to a match base result.

class RegEx

A regular expression that is compiled eagerly or on its first use.

The instance is immutable and can safely be shared between threads. A lazy expression compiles its engine exactly once on first use. If compilation fails, the matching operation throws RegExError; a later operation retries compilation. All Core-string overloads decode malformed units as replacement characters. Exceptions from custom inputs propagate unchanged.

Public Types

using ReplaceFn = std::function<text::String(MatchPtr)>

A callback that creates replacement text for one match.

Public Functions

inline const text::AnyString &pattern() const noexcept

Return the source pattern used to compile this regular expression.

Returns:

The preserved source pattern.

bool isCompiled() const noexcept

Test if the engine was successfully compiled.

Eager expressions always return true. This method does not trigger lazy compilation.

void compileNow() const

Compile a lazy expression now, or do nothing if its engine is already available.

Throws:

RegExError – If the pattern is invalid.

MatchPtr match(const text::String &text) const

Try to match this expression at the start of UTF-8 text.

Match16Ptr match(const text::U16String &text) const

Try to match this expression at the start of UTF-16 text.

Match32Ptr match(const text::U32String &text) const

Try to match this expression at the start of UTF-32 text.

MatchPtr match(const InputPtr &input) const

Try to match this expression at the start of a custom UTF-8 input.

MatchPtr match(const stream::TextInputStreamPtr &input) const

Try to match this expression at the current position of a seekable text stream.

Throws:
  • err::ParameterError – if the stream is null or does not support positioning.

  • stream::StreamError – if the stream times out or fails.

Match16Ptr match(const Input16Ptr &input) const

Try to match this expression at the start of a custom UTF-16 input.

Match32Ptr match(const Input32Ptr &input) const

Try to match this expression at the start of a custom UTF-32 input.

MatchPtr fullMatch(const text::String &text) const

Try to match this expression against all UTF-8 text.

Match16Ptr fullMatch(const text::U16String &text) const

Try to match this expression against all UTF-16 text.

Match32Ptr fullMatch(const text::U32String &text) const

Try to match this expression against all UTF-32 text.

MatchPtr fullMatch(const InputPtr &input) const

Try to match this expression against the complete custom UTF-8 input.

MatchPtr fullMatch(const stream::TextInputStreamPtr &input) const

Try to match this expression against all remaining text in a seekable text stream.

Throws:
  • err::ParameterError – if the stream is null or does not support positioning.

  • stream::StreamError – if the stream times out or fails.

Match16Ptr fullMatch(const Input16Ptr &input) const

Try to match this expression against the complete custom UTF-16 input.

Match32Ptr fullMatch(const Input32Ptr &input) const

Try to match this expression against the complete custom UTF-32 input.

MatchPtr findFirst(const text::String &text) const

Find the first match in UTF-8 text.

Match16Ptr findFirst(const text::U16String &text) const

Find the first match in UTF-16 text.

Match32Ptr findFirst(const text::U32String &text) const

Find the first match in UTF-32 text.

MatchPtr findFirst(const InputPtr &input) const

Find the first match in a custom UTF-8 input.

MatchPtr findFirst(const stream::TextInputStreamPtr &input) const

Find the first match in a seekable text stream.

Throws:
  • err::ParameterError – if the stream is null or does not support positioning.

  • stream::StreamError – if the stream times out or fails.

Match16Ptr findFirst(const Input16Ptr &input) const

Find the first match in a custom UTF-16 input.

Match32Ptr findFirst(const Input32Ptr &input) const

Find the first match in a custom UTF-32 input.

MatchGenerator findAll(const text::String &text) const

Lazily find all matches in UTF-8 text.

Match16Generator findAll(const text::U16String &text) const

Lazily find all matches in UTF-16 text.

Match32Generator findAll(const text::U32String &text) const

Lazily find all matches in UTF-32 text.

MatchGenerator findAll(InputPtr input) const

Lazily find all matches in a custom UTF-8 input.

MatchGenerator findAll(stream::TextInputStreamPtr input) const

Lazily find all matches in a seekable text stream.

Throws:
  • err::ParameterError – if the stream is null or does not support positioning.

  • stream::StreamError – if the stream times out or fails.

Match16Generator findAll(Input16Ptr input) const

Lazily find all matches in a custom UTF-16 input.

Match32Generator findAll(Input32Ptr input) const

Lazily find all matches in a custom UTF-32 input.

MatchList collectAll(const text::String &text) const

Collect all matches in UTF-8 text.

Match16List collectAll(const text::U16String &text) const

Collect all matches in UTF-16 text.

Match32List collectAll(const text::U32String &text) const

Collect all matches in UTF-32 text.

MatchList collectAll(const InputPtr &input) const

Collect all matches in a custom UTF-8 input.

MatchList collectAll(const stream::TextInputStreamPtr &input) const

Collect all matches in a seekable text stream.

Throws:
  • err::ParameterError – if the stream is null or does not support positioning.

  • stream::StreamError – if the stream times out or fails.

Match16List collectAll(const Input16Ptr &input) const

Collect all matches in a custom UTF-16 input.

Match32List collectAll(const Input32Ptr &input) const

Collect all matches in a custom UTF-32 input.

text::String replaceAll(const text::String &text, const text::String &replacementExpression) const

Replace all matches in UTF-8 text using a replacement expression.

text::String replaceAll(const text::String &text, const ReplaceFn &replaceFn) const

Replace all matches in UTF-8 text using a callback.

Public Static Functions

static RegExPtr compile(text::AnyString pattern, Flags flags = {}, const Settings &settings = {})

Compile a regular expression from a UTF-8 pattern.

Parameters:
  • pattern – The regular expression pattern.

  • flags – The initial flags for the regular expression.

  • settings – The settings for the parser and resulting engine.

Throws:

RegExError – If the pattern is invalid.

Returns:

A shared pointer to the compiled regular expression.

static RegExPtr lazyCompile(text::AnyString pattern, Flags flags = {}, const Settings &settings = {})

Create a regular expression whose engine is compiled on first use.

The pattern is retained without validation. Call compileNow() to explicitly trigger compilation.

Parameters:
  • pattern – The regular expression pattern.

  • flags – The initial flags for the regular expression.

  • settings – The settings for the parser and resulting engine.

Returns:

A shared pointer to the lazy regular expression.

struct PrivateTag
using erbsland::re::RegExPtr = std::shared_ptr<RegEx>

A shared pointer to a regular expression.

using erbsland::re::ConstRegExPtr = std::shared_ptr<const RegEx>

A shared pointer to an immutable regular expression.

class RegExError : public erbsland::err::RuntimeError

An error raised by regular-expression parsing, compilation, diagnostics, or matching.

See: Regular Expressions

Public Functions

RegExError(ErrorCategory category, text::String title) noexcept

Create an error with a concise title.

RegExError(ErrorCategory category, text::String title, unit::CodeLocation location) noexcept

Create an error with a title and source location.

RegExError(ErrorCategory category, text::String title, text::String description, unit::CodeLocation location = {}) noexcept

Create an error with a title, description, and optional source location.

explicit RegExError(RegExErrorContext context) noexcept

Create an error from complete context.

virtual text::String toString() const noexcept override

Create a compact one-line summary containing category, title and description.

virtual err::DiagnosticConstPtr diagnostic() const override

Create the complete structured diagnostic.

inline const RegExErrorContext &context() const noexcept

Get the complete error context.

inline ErrorCategory category() const noexcept

Get the error category.

inline const text::String &title() const noexcept

Get the concise error title.

inline const text::String &description() const noexcept

Get the detailed error description.

inline unit::CodeLocation location() const noexcept

Get the source location.

inline unit::LineIndex line() const noexcept

Get the source line index.

inline unit::ColumnIndex column() const noexcept

Get the source column index.

inline unit::CpIndex position() const noexcept

Get the source code-point position.

RegExError withLineNumber(unit::LineIndex lineNumber) const noexcept

Create a copy of this error with the given zero-based line index.

class RegExErrorContext

Context for a regular-expression error.

Public Functions

inline explicit RegExErrorContext(ErrorCategory category, text::String title, text::String description = {}, unit::CodeLocation location = {}) noexcept

Create context for a regular-expression error.

Parameters:
  • category – The error category.

  • title – A concise description of what went wrong.

  • description – An optional explanation of why the error occurred.

  • location – The optional source location.

inline ErrorCategory category() const noexcept

Get the error category.

inline RegExErrorContext &setCategory(const ErrorCategory category) noexcept

Set the error category.

inline const text::String &title() const noexcept

Get the concise error title.

inline RegExErrorContext &setTitle(text::String title) noexcept

Set the concise error title.

inline const text::String &description() const noexcept

Get the detailed error description.

inline RegExErrorContext &setDescription(text::String description) noexcept

Set the detailed error description.

inline unit::CodeLocation location() const noexcept

Get the source location.

inline RegExErrorContext &setLocation(const unit::CodeLocation location) noexcept

Set the source location.

inline unit::LineIndex line() const noexcept

Get the source line index.

inline unit::ColumnIndex column() const noexcept

Get the source column index.

inline unit::CpIndex position() const noexcept

Get the source code-point position.

class Settings

Settings for compiling regular expression patterns.

Public Functions

inline unit::CpLength maximumPatternLength() const noexcept

The maximum pattern length in characters.

inline void setMaximumPatternLength(unit::CpLength length) noexcept

Set the maximum pattern length.

Parameters:

length – A length in characters, or zero to reset back to default.

inline std::size_t maximumGroupNestingDepth() const noexcept

The maximum group nesting depth.

inline void setMaximumGroupNestingDepth(std::size_t depth) noexcept

Set the maximum group nesting depth.

Parameters:

depth – A depth in levels, or zero to reset back to default.

inline std::size_t maximumCaptureGroupCount() const noexcept

The maximum capture group count.

inline void setMaximumCaptureGroupCount(std::size_t count) noexcept

Set the maximum capture group count.

Parameters:

count – The maximum capture group count or zero to reset back to default.

inline std::size_t maximumSequenceLength() const noexcept

The maximum sequence length.

inline void setMaximumSequenceLength(std::size_t length) noexcept

Set the maximum sequence length.

Parameters:

length – A length in characters, or zero to reset back to default.

inline std::size_t maximumAlternativeCount() const noexcept

The maximum alternative count.

inline void setMaximumAlternativeCount(std::size_t count) noexcept

Set the maximum alternative count.

Parameters:

count – A count of alternatives, or zero to reset back to default.

inline std::size_t maximumQuantifierCount() const noexcept

Get the maximum quantifier count.

This is the maximum for quantifier expressions like {n,m}

inline void setMaximumQuantifierCount(std::size_t count) noexcept

Set the maximum quantifier count.

Parameters:

count – The maximum quantifier count, or zero to reset back to default.

inline std::chrono::milliseconds timeout() const noexcept

Access the current timeout.

Returns:

The current timeout. Zero means no timeout.

inline void setTimeout(const std::chrono::milliseconds timeout) noexcept

Set a timeout for all calls.

Parameters:

timeout – The timeout to set, or zero to disable timeout.

inline bool hasFeature(const Feature feature) const noexcept

Test if a feature is enabled.

Parameters:

feature – The feature to test.

inline void disableFeature(const Feature feature) noexcept

Disable a feature.

Parameters:

feature – The feature to disable.

inline void enableFeature(const Feature feature) noexcept

Enable a feature.

Parameters:

feature – The feature to enable.

inline text::String toString() const

Create a string representation for this settings object.