onigmo

package module
v0.0.0-...-7a21e30 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

README

go-ruby-regexp/regexp

regexp — go-ruby-regexp

Docs License Go Phase

A pure-Go (no cgo) reimplementation of Onigmo, the regular-expression engine used by Ruby — a faithful backtracking VM with the features RE2 (Go's standard regexp) deliberately omits: backreferences, lookahead/lookbehind, possessive quantifiers, atomic groups, named groups, subexpression calls, and Ruby's leftmost-first match semantics.

It is the regexp backend for go-embedded-ruby, but is a standalone, reusable module with no dependency on the Ruby runtime.

Status: Phases 0–4 complete — a greedy backtracking VM with leftmost-first semantics covering literals/escapes, ., character classes, anchors (\A \z \Z ^ $), greedy, non-greedy/lazy, and possessive quantifiers (* + ? {m,n}, *? +? ?? {m,n}?, and *+ ++ ?+) plus atomic groups (?>…), capturing and non-capturing groups, alternation, named groups (?<name>…) and backreferences \1 / \k<name>, plus lookahead (?=…) / (?!…), fixed-width lookbehind (?<=…) / (?<!…), the \G anchor, and subexpression calls \g<…> (named/numbered/relative/\g<0>, recursive), and from Phase 3 POSIX bracket classes [[:alpha:]][[:^digit:]] (the 14 standard classes, positive and negated) inside character classes, and the inline options (?imx) / (?imx:…) (with (?-…) to turn them off) — i case-insensitive matching (rune-level folding of literals and classes via unicode.SimpleFold, so /É/i matches é, (?i)[α-ω] an uppercase Greek letter, and /k/i even the Kelvin sign; backreferences fold ASCII-only), m dot-all (the dot also matches a newline), and x extended/free-spacing (unescaped whitespace and # comments ignored, except in a class) — and Unicode property classes \p{…} / \P{…} (general categories L N P S Z C + Lu Ll Lt Lm Lo Nd, plus the Onigmo aliases Alpha Alnum Digit Space Upper Lower Word, with \p{^…} negation and embedding inside character classes), the hex-digit classes \h / \H ([0-9A-Fa-f] and its complement), and the linebreak escape \R (a CRLF matched atomically, or any one of \n \r \v \f and the Unicode NEL/LS/PS) — all differential-tested against MRI, 100% coverage, CI green across 6 arches. Variable-width lookbehind is rejected, as in Onigmo/Ruby. ReDoS memoization (Phase 4) is in: a backreference-free pattern memoizes its (instruction, position) split states, so catastrophic patterns like (a+)+$ run in polynomial rather than exponential time (with the step budget as the backstop), producing the identical leftmost-first match.

Start-position prefilter (Phase 4) is in: the optimizer derives, where it can, a \A anchor, a required literal prefix, or a leading first-byte set from the compiled program — including the union over a leading alternation (foo|bar{f,b}, a*b{a,b}) — and uses it to skip start positions that provably cannot begin a match (a strings.Index / byte-set scan instead of running the VM at every offset). It is fully transparent — every candidate is still verified by the VM, so results are byte-identical — and gives ~200× on a literal-prefixed scan of a long non-matching haystack.

Required-interior-literal prefilter (Phase 4) is in: even with no anchor and no leading literal, the optimizer extracts a fixed substring that must appear somewhere inside every match (the foo of \d+foo\d+, the xyz of [ab]*xyz[cd]*) by walking the program's mandatory spine across quantifiers, captured groups, and lookarounds but never across an alternation. A single strings.Contains then rejects a whole haystack lacking it before the VM runs at any offset, and the literal's last occurrence bounds the scan on the right (no match can begin past it). It stays transparent (the VM still verifies every survivor) and gives ~108× on a 90 KB non-matching haystack the start-locating filters cannot exploit.

Wall-clock timeout (Phase 4) is in: re.WithTimeout(d) returns a copy that aborts any single match exceeding d of real time (Ruby's Regexp.timeout equivalent), the real-time backstop to the deterministic step budget. The receiver is left unchanged, so a shared *Regexp stays concurrency-safe; the VM polls the clock only once every 4096 steps, so a search with no deadline pays nothing.

Benchmarks & transparent allocation reuse (Phase 4) are in: a representative suite (bench_test.go) covers literal-prefix and alternation scanning, anchored matching, backtracking-heavy nested quantifiers under the ReDoS memo, subexpression-call recursion, multibyte/UTF-8 and binary scanning, and the prefilter fast paths against a forced-slow baseline. The start-position scan now reuses one capture buffer across offsets instead of reallocating at each (the VM never writes the base buffer in place, so this is behaviour-preserving), cutting the forced-slow whole-haystack baseline from ~270 k to ~180 k allocations. The prefilter fast paths run at ~15.6 µs versus ~3.37 ms for that baseline (~210×) on a 90 KB non-matching haystack, and an active WithTimeout adds ~2 % (polling noise). The engine roadmap (Phases 0–4) is complete — see the Engine status: complete section of docs/plan-regexp.md for the full supported-feature list and the documented out-of-scope boundaries.

Rune/byte boundary. \p{…} and a folded (/i) literal or class are the rune-aware atoms: each decodes one UTF-8 code point and advances by its byte length (a \p{…} member, or /i, also makes the enclosing character class rune-aware). Folding is simple (1:1) only — full/special folding (ßss, Turkish dotless-i) is out of scope. Match offsets are byte offsets (MRI reports character offsets, so the engines agree on matched text but not on the numeric span on multi-byte input); a rune-aware atom never matches at a UTF-8 continuation byte and is rejected inside a fixed-width lookbehind.

Multi-encoding (Regexp#encoding). A Regexp carries a first-class encoding (re.Encoding()), the way Ruby's Regexp#encoding governs matching on a UTF-8 versus a binary string. In the default UTF8 mode the dot . and a byte-oriented class advance by a whole UTF-8 code point, so /./ matches a complete multi-byte character (/./ on "é" consumes "é", and [^a] consumes a whole character — exactly as MRI; a positive ASCII range like [a-z] still fails on a multi-byte character). In ASCII8BIT mode (Ruby's binary /n, via CompileEnc(pattern, ASCII8BIT)) every atom advances one byte and /i folding and \p{…} operate per byte, ASCII-only. A bare ./byte-class inside a fixed-width lookbehind has variable byte width (1..4) in UTF8 mode and the candidate-position scan finds the character-aligned start, so (?<=.)x matches. A literal multi-byte character-class member is a whole code point in UTF8 mode: [é] matches "é", [à-ï] is a code-point range, [αβγ]/[中文] work, a mixed class such as [a-zé] combines an ASCII range with a multi-byte member, and a range may span ASCII into the multi-byte space ([a-é]). In ASCII8BIT mode such a member stays byte-oriented ([é] is its two raw bytes). Encodings beyond UTF-8 / ASCII-8BIT (UTF-16/32, EUC, Shift_JIS) are out of scope: a Go string is UTF-8 by convention, so legacy/wide text is transcoded to UTF-8 at the boundary before matching.

Subexpression calls (\g<…>). \g<name>, \g<n>, relative \g<+n> / \g<-n>, and \g<0> (whole-pattern recursion) re-run and re-capture the referenced group, with last-execution-wins captures except that a self-recursive group keeps its outermost binding — exactly as Onigmo/Ruby. Forward references resolve post-parse; recursive and mutually recursive grammars (e.g. balanced parentheses \A(?<bal>\((?:[^()]|\g<bal>)*\))\z) work. A per-search call/return stack drives this, with a hard recursion-depth cap plus the step budget so a non-terminating grammar fails deterministically. A call has data-dependent width, so it is rejected inside a fixed-width lookbehind. See docs/plan-regexp.md for the architecture and roadmap.

Why not the standard library?

Go's regexp is RE2: linear-time but without backreferences or lookaround, and with different (leftmost-longest) semantics. Ruby code routinely depends on Onigmo features RE2 cannot express, so a byte-compatible Ruby regexp needs a backtracking engine. This module provides one, hardened against catastrophic backtracking with memoization and a deterministic time/step budget.

License

BSD-3-Clause. See LICENSE.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package onigmo is a pure-Go (cgo-free) reimplementation of Onigmo, the regular-expression engine used by Ruby.

Unlike Go's standard library regexp (RE2), it is a backtracking VM and so can support the Onigmo features RE2 omits — backreferences, lookahead/lookbehind, possessive quantifiers, atomic groups, named groups and subexpression calls — with Ruby's leftmost-first match semantics, hardened against catastrophic backtracking (ReDoS) by memoization and a deterministic time/step budget.

Phase 0 is implemented: a greedy backtracking VM with leftmost-first match semantics covering literals and escapes, the dot metacharacter, character classes (ranges, negation, and the \d \D \w \W \s \S escapes), the anchors \A \z \Z ^ $, the greedy quantifiers * + ? {m} {m,} {m,n}, capturing and non-capturing groups, and alternation. Phase 1 adds named groups (?<name>...), backreferences (\1..\9 and \k<name>), and the non-greedy (lazy) quantifiers *? +? ?? {m,n}? (which match the fewest repetitions first, so <.+?> matches the shortest tag) and the possessive quantifiers *+ ++ ?+ and atomic groups (?>...) (which commit a matched span — once it matches, its backtrack points are discarded, so a++a and (?>a+)a never match "aaa"; a trailing + on a {m,n} brace is instead a stacked greedy repeat, as in Onigmo). Phase 2 adds the lookaround assertions — positive and negative lookahead (?=...) (?!...) and lookbehind (?<=...) (?<!...) — and the \G anchor (which pins a match to the scan start). Lookbehind bodies must be of constant width per alternative, as in Onigmo/Ruby; variable-width lookbehind is rejected. Phase 3 begins with POSIX bracket classes [[:name:]] (and negated [[:^name:]]) inside character classes, for the 14 standard names alpha, digit, alnum, upper, lower, space, blank, cntrl, graph, print, punct, xdigit, and word; and the inline options (?flags) / (?flags:...) (with the (?-flags) turn-off form) for the letters i (case-insensitive matching), m (dot-all: the dot also matches a newline), and x (extended/free-spacing: unescaped whitespace and # comments in the pattern are ignored, except inside a character class).

Under /i, literals and character classes fold rune-aware using Go's unicode.SimpleFold (simple, 1:1 case folding): a folded character is decoded as a whole UTF-8 code point and matches any code point in its simple-case-folding orbit, so /É/i matches é, Greek and Cyrillic case pairs fold, and even ASCII /k/i reaches the Kelvin sign U+212A. A folded class is rune-aware too (so (?i)[a-z] matches A and the Kelvin sign, and (?i)[α-ω] an uppercase Greek letter), with multi-byte members and ranges and last-applied negation. A folded atom obeys the same rune/byte boundary as \p{…} (it never matches at a UTF-8 continuation byte, keeps byte offsets, and is rejected inside a fixed-width lookbehind). Only simple folding is done: full/special folding (ß→"ss", Turkish dotless-i) is out of scope, and backreference folding stays ASCII-only.

Phase 3 also adds Unicode property classes \p{name} / \P{name} (and the in-brace negation \p{^name}), the one rune-aware atom in the otherwise byte-oriented engine: it decodes a single UTF-8 code point and advances by its byte length. The supported names are the general categories L, N, P, S, Z, C and the letter/number subcategories Lu, Ll, Lt, Lm, Lo, Nd, plus the Onigmo POSIX-style aliases Alpha, Alnum, Digit, Space, Upper, Lower and Word (following Ruby's definitions). A property may also appear inside a character class ([\p{L}\d]), which makes that class rune-aware while its ASCII byte-range members keep working. A rune-aware atom never matches at a UTF-8 continuation byte, so the scan never tests a code point mid-character (as MRI, which positions by character). Note that match offsets remain byte offsets, whereas MRI reports character offsets, so the two agree on matched text but not on the numeric span on multi-byte input. (Rune-level Unicode case-folding for /i is described above.)

Multi-encoding (Phase 3) gives the Regexp a first-class encoding, matching the way Ruby's Regexp#encoding governs matching on a UTF-8 versus a binary string. In the default UTF8 mode the dot (.) and a byte-oriented character class advance by a whole UTF-8 code point, so /./ matches a complete multi-byte character — /./ on "é" consumes "é" as one unit, and [^a] consumes a whole character rather than a single byte, exactly as MRI does on a UTF-8 string (a positive ASCII range such as [a-z] still fails on a multi-byte character, whose code point exceeds the range). This resolves the engine's original "dot matches one byte" limitation. In ASCII8BIT mode (Ruby's binary /n encoding, selected by CompileEnc(pattern, ASCII8BIT)) every atom advances a single byte and Unicode case-folding (/i) and \p{…} properties operate per byte, ASCII-only. The encoding is exposed as re.Encoding(). Match offsets are byte offsets in both modes. In UTF8 mode a bare . or a byte-oriented class inside a fixed-width lookbehind has a variable byte width (1..4); the lookbehind's candidate-position scan enumerates the alignments and only a code-point-aligned one matches, so a lookbehind over a multi-byte character works ((?<=.)x matches the x after "é"). A literal multi-byte character-class member is a whole code point in UTF8 mode: [é] matches "é", [à-ï] is a code-point range, [αβγ]/[中文] work, a mixed class such as [a-zé] combines an ASCII range with a multi-byte member, and a range may span ASCII into the multi-byte space ([a-é]); in ASCII8BIT mode such a member stays byte-oriented ([é] is its two raw bytes). Per-encoding cursors beyond UTF-8 and ASCII-8BIT (UTF-16/32, EUC, Shift_JIS) are deliberately out of scope: a Go string is UTF-8 by convention, and text in a legacy or wide encoding is transcoded to UTF-8 at the boundary before matching.

Phase 3 also adds the hex-digit class \h (Onigmo's [0-9A-Fa-f]) and its byte-complement \H — usable standalone or inside a character class, and byte-oriented like \d/\w — and the linebreak escape \R, lowered to (?>\r\n|[\n\v\f\r\x{85}\x{2028}\x{2029}]): a CR-LF pair matches atomically as one unit (so \R\n never splits a CRLF) and a lone \n, \r, \v, \f, NEL, LS or PS also matches. \R is rune-aware (it carries the multi-byte NEL/LS/PS members), so like \p{…} it decodes a whole code point and is rejected inside a fixed-width lookbehind.

Subexpression calls \g<…> are implemented: \g<name>, \g<n> (absolute group number), the relative forms \g<+n> / \g<-n>, and \g<0> (recurse the whole pattern). A call is a true re-execution of the referenced group's sub-pattern at the current position, and it re-captures into that group's slot, so the most recent execution wins — except that a group recursing into itself keeps its outermost binding, exactly as Onigmo/Ruby does (the engine saves and restores the open groups' captures across a call). Calls may be recursive and mutually recursive, so the balanced-parentheses idiom \A(?<bal>\((?:[^()]|\g<bal>)*\))\z works. Forward references (calling a group defined later) resolve in a post-parse pass. Recursion is bounded by a hard depth cap plus the step budget, so a pathological or non-terminating grammar (e.g. \A\g<0>\z, which Onigmo rejects statically) fails deterministically rather than exhausting the Go stack. A call has data/recursion-dependent width, so — like a backreference — it is rejected inside a fixed-width lookbehind (a documented divergence: MRI accepts the simple one-char case).

ReDoS hardening (Phase 4) is in: for a pattern without a backreference or a subexpression call the VM memoizes the (instruction, position) split states it has explored and never re-explores one, so catastrophic patterns such as (a+)+$ run in polynomial rather than exponential time while producing the identical leftmost-first match. A deterministic step budget (and, for calls, the recursion-depth cap) remains as the backstop, joined by an optional wall-clock timeout (Ruby's Regexp.timeout equivalent): re.WithTimeout(d) returns a concurrency-safe copy that aborts a match exceeding d of real time, reporting no match. A pathological pattern is bounded by whichever of the budget or the deadline it reaches first.

A transparent prefilter (Phase 4) accelerates the search. The start-position pass analyses the compiled program's leading path for a \A anchor, a required literal prefix, or a first-byte set — including the union over a leading alternation (foo|bar, a*b) — and uses it to skip start positions that cannot begin a match (a strings.Index or byte-set scan instead of invoking the VM at every offset). A second pass extracts a required interior literal — a fixed substring that must appear somewhere in every match even when the pattern has no anchor or leading literal (the foo of \d+foo\d+) — by walking the program's mandatory spine, rejects a whole haystack lacking it with a single strings.Contains, and bounds the scan on the right at the literal's last occurrence (no match can begin past it). Every candidate either pass yields is still verified by the VM, so results are byte-identical to an unfiltered scan. The start-position scan also reuses a single capture buffer across the offsets it tries rather than reallocating at each — the VM never writes that base buffer in place, so the reuse is behaviour-preserving — and a representative benchmark suite (bench_test.go) measures the literal/alternation/anchored/backtracking/ subexpression-call/multibyte workloads and the prefilter fast paths against a forced-slow baseline.

With these, the standalone engine roadmap (Phases 0–4) is complete. The full supported-feature list and the deliberately documented out-of-scope boundaries (full/special case folding, the \p{…} category slice, encodings beyond UTF-8/ASCII-8BIT, byte rather than character offsets, lenient invalid-UTF-8 decoding, and variable-width lookbehind) are collected in the "Engine status: complete" section of docs/plan-regexp.md. The Ruby Regexp/MatchData surface and the replacement DSL (Phase 5) live in the downstream go-embedded-ruby adapter that consumes this module, not here.

See docs/plan-regexp.md for the full roadmap.

Index

Constants

View Source
const (
	// UTF8 is the default encoding: the dot and byte-oriented classes advance by
	// a whole UTF-8 code point.
	UTF8 = compile.UTF8
	// ASCII8BIT is Ruby's binary (/n) encoding: every atom advances one byte.
	ASCII8BIT = compile.ASCII8BIT
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Encoding

type Encoding = compile.Encoding

Encoding selects how the byte-oriented input-advancing atoms — the dot (`.`) and a byte-oriented character class — traverse the input, the way Ruby's Regexp#encoding governs matching on a UTF-8 vs a binary (ASCII-8BIT) string.

In UTF8 (the default) the dot and byte-oriented classes advance by a whole UTF-8 code point, so `/./` matches a complete multi-byte character (it matches "é" as one unit, exactly as MRI does on a UTF-8 string) and `[^a]` consumes a whole character rather than a single byte. In ASCII8BIT (Ruby's /n binary encoding) every atom advances one byte, and Unicode case-folding (/i) and \p{…} properties operate per byte (ASCII-only). Match offsets are byte offsets in both modes.

type MatchData

type MatchData struct {
	// contains filtered or unexported fields
}

MatchData holds the result of a successful match: the byte spans of the whole match (group 0) and of each capturing group.

func (*MatchData) Begin

func (m *MatchData) Begin(i int) int

Begin returns the byte offset of the start of group i, or -1 if the group did not participate in the match. Group 0 is the whole match. An out-of-range index returns -1.

func (*MatchData) End

func (m *MatchData) End(i int) int

End returns the byte offset just past the end of group i, or -1 if the group did not participate. An out-of-range index returns -1.

func (*MatchData) IndexOfName

func (m *MatchData) IndexOfName(name string) int

IndexOfName returns the 1-based group index for a named capture, or -1 if no group has that name.

func (*MatchData) NGroups

func (m *MatchData) NGroups() int

NGroups returns the number of capturing groups, not counting group 0 (the whole match).

func (*MatchData) Post

func (m *MatchData) Post() string

Post returns the portion of the input after the whole match.

func (*MatchData) Pre

func (m *MatchData) Pre() string

Pre returns the portion of the input before the whole match.

func (*MatchData) Str

func (m *MatchData) Str(i int) string

Str returns the substring matched by group i, or the empty string if the group did not participate or the index is out of range.

func (*MatchData) StrName

func (m *MatchData) StrName(name string) string

StrName returns the substring captured by the named group, or "" if there is no such name or the group did not participate.

type Regexp

type Regexp struct {
	// contains filtered or unexported fields
}

Regexp is a compiled regular expression, safe for concurrent use by multiple goroutines. A Regexp is immutable once compiled; WithTimeout returns a copy carrying a wall-clock match limit rather than mutating the receiver, so a shared Regexp stays concurrency-safe. The heavy matcher state lives behind the shared *machine, built lazily on first match; the copy WithTimeout returns shares that machine, so a timeout variant never rebuilds it.

func Compile

func Compile(pattern string) (*Regexp, error)

Compile parses a pattern and returns a compiled Regexp in the default UTF-8 encoding, or an error if the pattern is malformed.

func CompileEnc

func CompileEnc(pattern string, enc Encoding) (*Regexp, error)

CompileEnc is Compile with an explicit input encoding (see Encoding). UTF8 makes the dot and byte-oriented classes advance by a whole code point; ASCII8BIT makes every atom advance one byte, matching Ruby's /n.

func (*Regexp) Encoding

func (re *Regexp) Encoding() Encoding

Encoding returns the input encoding the Regexp matches under (Ruby's Regexp#encoding equivalent): UTF8 by default, ASCII8BIT for a binary pattern. It is answered from the stored encoding and does not trigger the deferred machine build.

func (*Regexp) Match

func (re *Regexp) Match(s string) *MatchData

Match searches s for the leftmost match and returns a *MatchData, or nil if there is no match. The search scans start positions left to right and, at the first position that matches, returns the greedy leftmost-first match (Ruby / Onigmo semantics).

If the Regexp carries a timeout (see WithTimeout) and the search exceeds it, or the internal step budget is exhausted, Match returns nil — a pathological pattern is bounded rather than allowed to run unboundedly.

func (*Regexp) MatchAt

func (re *Regexp) MatchAt(s string, pos int) *MatchData

MatchAt attempts a match anchored exactly at byte offset pos in s, with \G bound to pos. It does not scan forward: it matches at pos or returns nil. The whole string s stays visible to the matcher, so the line/text anchors (^, \A) and lookbehind see the real prefix s[:pos] — exactly the semantics a StringScanner-style tokenizer needs (a Rouge RegexLexer scanning a buffer in place). Group offsets in the returned MatchData are absolute into s.

This is the faithful primitive for cursor-anchored lexing: pattern ^ matches only at a genuine line start, not merely at pos. A timeout or exhausted step budget yields nil, as with Match.

func (*Regexp) MatchBounds

func (re *Regexp) MatchBounds(s string) (begin, end int, ok bool)

MatchBounds is the allocation-free, bounds-only form of Match: it scans s left to right for the leftmost match and returns its whole-match [begin, end) byte span, without building a MatchData or extracting submatches. It is the primitive for a forward StringScanner scan_until / skip_until whose captured text the caller ignores. On the lazy-NFA subset the search is the linear-time NFA on pooled state (no per-call allocation); otherwise it falls to the backtracking VM (bounded by the step budget). The span is identical to Match(s).Begin(0)/End(0).

func (*Regexp) MatchBoundsAt

func (re *Regexp) MatchBoundsAt(s string, pos int) (begin, end int, ok bool)

MatchBoundsAt is the allocation-free, bounds-only form of MatchAt: it reports the whole match's [begin, end) byte span for a match anchored exactly at pos (begin == pos on success), without building a MatchData or extracting submatches. It is the primitive for the cursor-anchored StringScanner ops that need only a length or a yes/no — skip(/…/), match?(/…/), an anchored scan whose captured text the caller ignores — mirroring Ruby's StringScanner#skip / #match?, which likewise return an integer rather than a MatchData. When the program is in the lazy-NFA subset (no backreference, call, lookaround, atomic group, or over-large bounded loop) the span is found by the linear-time NFA on pooled state, so a tokenizing loop over such a pattern allocates nothing per call; otherwise it falls to the backtracking VM. The span is identical to MatchAt(s, pos).Begin(0)/End(0). pos out of range yields ok == false.

func (*Regexp) MatchString

func (re *Regexp) MatchString(s string) bool

MatchString reports whether s contains a match of the regular expression. When the program is in the lazy-NFA subset (no backreference, call, lookaround, atomic group, or over-large bounded loop) the is-match question is answered by the linear-time NFA simulation rather than the backtracking VM — one step per input position — even for a pattern with capturing groups, since whether a match exists never depends on which text the groups captured. The backtracking VM is used only for programs outside the subset.

func (*Regexp) String

func (re *Regexp) String() string

String returns the source pattern the Regexp was compiled from.

func (*Regexp) Timeout

func (re *Regexp) Timeout() time.Duration

Timeout returns the wall-clock limit applied to a single match, or zero if no limit is set.

func (*Regexp) WithTimeout

func (re *Regexp) WithTimeout(d time.Duration) *Regexp

WithTimeout returns a copy of the Regexp that aborts any single match taking longer than d of wall-clock time (Ruby's Regexp.timeout equivalent), returning no match. A non-positive d clears the limit. The copy shares the compiled program with the receiver, which is left unchanged, so a Regexp can be shared across goroutines and given per-use timeouts without data races.

Directories

Path Synopsis
internal
ast
Package ast holds the abstract syntax tree node types for the regular expression grammar.
Package ast holds the abstract syntax tree node types for the regular expression grammar.
charset
Package charset classifies a single Unicode code point against the property names this engine recognises for the \p{…} / \P{…} construct.
Package charset classifies a single Unicode code point against the property names this engine recognises for the \p{…} / \P{…} construct.
compile
Package compile lowers a syntax AST into the flat instruction program that the backtracking VM executes.
Package compile lowers a syntax AST into the flat instruction program that the backtracking VM executes.
syntax
Package syntax holds the scanner and recursive-descent parser that turn an Onigmo/Ruby regular-expression pattern into an abstract syntax tree (the node types live in the sibling ast package).
Package syntax holds the scanner and recursive-descent parser that turn an Onigmo/Ruby regular-expression pattern into an abstract syntax tree (the node types live in the sibling ast package).
vm
Package vm executes a compiled program against an input using explicit backtracking with greedy, leftmost-first semantics (as in Ruby/Onigmo).
Package vm executes a compiled program against an input using explicit backtracking with greedy, leftmost-first semantics (as in Ruby/Onigmo).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL