diff --git a/.gitignore b/.gitignore index b9566aa..3bee624 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ compile_flags.txt benchmark/run_output.yaml benchmark/*.txt x.txt +y.txt +testdata/pcre/JSON-PP-4.16 diff --git a/Benchmark.lean b/Benchmark.lean index b8d6d3e..a608621 100644 --- a/Benchmark.lean +++ b/Benchmark.lean @@ -56,7 +56,7 @@ def main (args : List String): IO Unit := do IO.println s!"re {re} haystack {haystack}" let nl := "\n" - let regex ← build re default ⟨true⟩ + let regex ← build re default default ⟨true⟩ match Regex.Log.captures haystack.toSubstring regex default (logEnabled := false) with | (msgs, none) => if msgs.size > 0 then IO.println s!"msgs {msgs |> Array.map (· ++ nl)}" @@ -75,7 +75,7 @@ def main (args : List String): IO Unit := do let haystack := a IO.println s!"re {re} haystack {haystack}" - let regex ← build re default ⟨true⟩ + let regex ← build re default default ⟨true⟩ let count := m.fold (init := 0) (fun acc _ => diff --git a/Main.lean b/Main.lean index 7b9579f..b79e3e0 100644 --- a/Main.lean +++ b/Main.lean @@ -75,6 +75,7 @@ usage: inspect [OPTIONS] COMMANDS: ast print the abstract syntax tree hir print the high level intermediate representation + compile print the nfa captures get first or all captures of in OPTIONS: @@ -101,19 +102,20 @@ where | '\\' :: 'x' :: a :: b :: tail => (toChar a b) :: (loop tail acc) | '\\' :: 'n' :: tail => '\n' :: (loop tail acc) | '\\' :: 'r' :: tail => '\r' :: (loop tail acc) + | '\\' :: 't' :: tail => '\t' :: (loop tail acc) | head :: tail => head :: (loop tail acc) def ast : CliM PUnit := do match ← takeArg? with | some re => - let ast ← AstItems.parse re + let ast ← AstItems.parse re default IO.println s!"Ast\n{ast}" | none => throw <| CliError.missingArg "re" def hir : CliM PUnit := do match ← takeArg? with | some re => - let ast ← AstItems.parse re + let ast ← AstItems.parse re default let hir ← Syntax.translate default ast IO.println s!"Hir\n{hir}" | none => throw <| CliError.missingArg "re" @@ -121,7 +123,7 @@ def hir : CliM PUnit := do def compile : CliM PUnit := do match ← takeArg? with | some pat => - let re ← build pat default ⟨true⟩ + let re ← build pat default default ⟨true⟩ IO.println s!"{re.nfa}" | none => throw <| CliError.missingArg "re" diff --git a/README.md b/README.md index 73adcb0..90e9431 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ A [regular expression](https://en.wikipedia.org/wiki/Regular_expression) engine written in [Lean 4](https://github.com/leanprover/lean4). -This library is heavily based on the [Rust regex crate](https://docs.rs/regex/latest/regex/). +This library is based on the [Rust regex crate](https://docs.rs/regex/latest/regex/) +and extended for compatibility with [Pcre](https://www.pcre.org/). Main restrictions: @@ -31,7 +32,7 @@ Get captures of "∀ (n : Nat), 0 ≤ n" : ```lean def Main : IO Unit := do - let re := regex% r"^\p{Math}\s*([^,]+),\s*(\p{Nd})\s*(\p{Math})\s*([a-z])$" + let re := regex% r"^\p{Math}\s*(.(?<=\()([a-z])[^,]+),\s*(\p{Nd})\s*(\p{Math})\s*\2$" let captures := Regex.captures "∀ (n : Nat), 0 ≤ n" re IO.println s!"{captures}" ``` @@ -40,8 +41,8 @@ Output is ```lean fullMatch: '∀ (n : Nat), 0 ≤ n', 0, 22 -groups: #[(some ('(n : Nat)', 4, 13)), (some ('0', 15, 16)), - (some ('≤', 17, 20)), (some ('n', 21, 22))] +groups: #[(some ('(n : Nat)', 4, 13)), (some ('n', 5, 6)), + (some ('0', 15, 16)), (some ('≤', 17, 20))] ``` Api @@ -51,10 +52,10 @@ Api Components of regular expression: -- *^* : Assertion Start of line - *\p{Math}* : match all characters with the Math property -- *\s\** : match white space +- *(?<=\\()* : lookbehind of char '(' - *(\p{Nd})* : capturing group of numeric characters +- *\2* : backreference to second capturing group ## Test diff --git a/Regex.lean b/Regex.lean index 533db8c..0d02e5a 100644 --- a/Regex.lean +++ b/Regex.lean @@ -10,7 +10,8 @@ import Regex.Notation A [regular expression](https://en.wikipedia.org/wiki/Regular_expression) engine written in [Lean 4](https://github.com/leanprover/lean4). -This library is heavily based on the [Rust regex crate](https://docs.rs/regex/latest/regex/). +This library is based on the [Rust regex crate](https://docs.rs/regex/latest/regex/) +and extended for compatibility with [Pcre](https://www.pcre.org/). Contents: @@ -23,195 +24,17 @@ Contents: ## Syntax -The [syntax](https://docs.rs/regex/latest/regex/#syntax) of the Rust regex crate is documented below. -The syntax is similar to Perl-style regular expressions, but lacks a few features like +There are to syntax flavors: -* [back references](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#SEC25), -* [look around assertions](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#SEC22). +- Pcre : compatibility with [Pcre](https://www.pcre.org/), +- Rust : compatibility with [Rust](https://docs.rs/regex/latest/regex/#syntax). -This library supports the Rust regex syntax except -* non unicode mode, -* verbose mode. +The following feature are not yet implemented in the Pcre flavor: -### Matching one character - -
-.             any character except new line (includes new line with s flag)
-[0-9]         any ASCII digit
-\d            digit (\p{Nd})
-\D            not digit
-\pX           Unicode character class identified by a one-letter name
-\p{Greek}     Unicode character class (general category or script)
-\PX           Negated Unicode character class identified by a one-letter name
-\P{Greek}     negated Unicode character class (general category or script)
-
- -### Character classes - -
-[xyz]           A character class matching either x, y or z (union).
-[^xyz]          A character class matching any character except x, y and z.
-[a-z]           A character class matching any character in range a-z.
-[[:alpha:]]     ASCII character class ([A-Za-z])
-[[:^alpha:]]    Negated ASCII character class ([^A-Za-z])
-[x[^xyz]]       Nested character class (matching any character except y and z)
-[a-y&&xyz]      Intersection (matching x or y)
-[0-9&&[^4]]     Subtraction using intersection and negation (matching 0-9 except 4)
-[0-9--4]        Direct subtraction (matching 0-9 except 4)
-[a-g~~b-h]      Symmetric difference (matching `a` and `h` only)
-[\\[\\]]          Escaping in character classes (matching [ or ])
-[a&&b]          An empty character class matching nothing
-
- -### Composites - -
-xy    concatenation (x followed by y)
-x|y   alternation (x or y, prefer x)
-
- -### Repetitions - -
-x*        zero or more of x (greedy)
-x+        one or more of x (greedy)
-x?        zero or one of x (greedy)
-x*?       zero or more of x (ungreedy/lazy)
-x+?       one or more of x (ungreedy/lazy)
-x??       zero or one of x (ungreedy/lazy)
-x{n,m}    at least n x and at most m x (greedy)
-x{n,}     at least n x (greedy)
-x{n}      exactly n x
-x{n,m}?   at least n x and at most m x (ungreedy/lazy)
-x{n,}?    at least n x (ungreedy/lazy)
-x{n}?     exactly n x
-
- -### Empty matches - -
-^               the beginning of a haystack (or start-of-line with multi-line mode)
-$               the end of a haystack (or end-of-line with multi-line mode)
-\A              only the beginning of a haystack (even with multi-line mode enabled)
-\z              only the end of a haystack (even with multi-line mode enabled)
-\b              a Unicode word boundary (\w on one side and \W, \A, or \z on other)
-\B              not a Unicode word boundary
-\b{start}       a Unicode start-of-word boundary (\W|\A on the left, \w on the right)
-\b{end}         a Unicode end-of-word boundary (\w on the left, \W|\z on the right))
-\b{start-half}  half of a Unicode start-of-word boundary (\W|\A on the left)
-\b{end-half}    half of a Unicode end-of-word boundary (\W|\z on the right)
-
- -The empty regex is valid and matches the empty string. For example, the -empty regex matches `abc` at positions `0`, `1`, `2` and `3`. - -### Grouping and flags - -
-(exp)          numbered capture group (indexed by opening parenthesis)
-(?P<name>exp)  named (also numbered) capture group (names must be alpha-numeric)
-(?<name>exp)   named (also numbered) capture group (names must be alpha-numeric)
-(?:exp)        non-capturing group
-(?flags)       set flags within current group
-(?flags:exp)   set flags for exp (non-capturing)
-
- -Capture group names must be any sequence of alpha-numeric Unicode codepoints, -in addition to `.`, `_`, `[` and `]`. Names must start with either an `_` or -an alphabetic codepoint. Alphabetic codepoints correspond to the `Alphabetic` -Unicode property, while numeric codepoints correspond to the union of the -`Decimal_Number`, `Letter_Number` and `Other_Number` general categories. - -Flags are each a single character. For example, `(?x)` sets the flag `x` -and `(?-x)` clears the flag `x`. Multiple flags can be set or cleared at -the same time: `(?xy)` sets both the `x` and `y` flags and `(?x-y)` sets -the `x` flag and clears the `y` flag. - -All flags are by default disabled unless stated otherwise. They are: - -
-i     case-insensitive: letters match both upper and lower case
-m     multi-line mode: ^ and $ match begin/end of line
-s     allow . to match \n
-R     enables CRLF mode: when multi-line mode is enabled, \r\n is used
-U     swap the meaning of x* and x*?
-u     Unicode support (always enabled, *-u* is ignored)
--u    non unicode support (*-u* is ignored)
-x     verbose mode, allow line comments (not implemented)
-
- -Multi-line mode means `^` and `$` no longer match just at the beginning/end of -the input, but also at the beginning/end of lines: - -### Escape sequences - -Note that this includes all possible escape sequences, even ones that are -documented elsewhere. - -
-\*              literal *, applies to all ASCII except [0-9A-Za-z<>]
-\a              bell (\x07)
-\f              form feed (\x0C)
-\t              horizontal tab
-\n              new line
-\r              carriage return
-\v              vertical tab (\x0B)
-\A              matches at the beginning of a haystack
-\z              matches at the end of a haystack
-\b              word boundary assertion
-\B              negated word boundary assertion
-\b{start}, \<   start-of-word boundary assertion
-\b{end}, \>     end-of-word boundary assertion
-\b{start-half}  half of a start-of-word boundary assertion
-\b{end-half}    half of a end-of-word boundary assertion
-\123            octal character code, up to three digits (when enabled)
-\x7F            hex character code (exactly two digits)
-\x{10FFFF}      any hex character code corresponding to a Unicode code point
-\u007F          hex character code (exactly four digits)
-\u{7F}          any hex character code corresponding to a Unicode code point
-\U0000007F      hex character code (exactly eight digits)
-\U{7F}          any hex character code corresponding to a Unicode code point
-\p{Letter}      Unicode character class
-\P{Letter}      negated Unicode character class
-\d, \s, \w      Perl character class
-\D, \S, \W      negated Perl character class
-
- -### Perl character classes (Unicode friendly) - -These classes are based on the definitions provided in -[UTS#18](https://www.unicode.org/reports/tr18/#Compatibility_Properties): - -
-\d     digit (\p{Nd})
-\D     not digit
-\s     whitespace (\p{White_Space})
-\S     not whitespace
-\w     word character (\p{Alphabetic} + \p{M} + \d + \p{Pc} + \p{Join_Control})
-\W     not word character
-
- -### ASCII character classes - -These classes are based on the definitions provided in -[UTS#18](https://www.unicode.org/reports/tr18/#Compatibility_Properties): - -
-[[:alnum:]]    alphanumeric ([0-9A-Za-z])
-[[:alpha:]]    alphabetic ([A-Za-z])
-[[:ascii:]]    ASCII ([\x00-\x7F])
-[[:blank:]]    blank ([\t ])
-[[:cntrl:]]    control ([\x00-\x1F\x7F])
-[[:digit:]]    digits ([0-9])
-[[:graph:]]    graphical ([!-~])
-[[:lower:]]    lower case ([a-z])
-[[:print:]]    printable ([ -~])
-[[:punct:]]    punctuation ([!-\/:-@\[-`{-~])
-[[:space:]]    whitespace ([\t\n\v\f\r ])
-[[:upper:]]    upper case ([A-Z])
-[[:word:]]     word characters ([0-9A-Za-z_])
-[[:xdigit:]]   hex digit ([0-9A-Fa-f])
-
+* [subroutines](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#SEC26), +* [conditional patterns](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#TOC1), +* [backtracking control](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#SEC28), +* [variable length look behind](https://pcre2project.github.io/pcre2/doc/html/pcre2syntax.html#SEC22). ## Unicode @@ -274,7 +97,7 @@ Get captures of "∀ (n : Nat), 0 ≤ n" :
 def Main : IO Unit := do
-  let re ← Regex.build r"^\p{Math}\s*([^,]+),\s*(\p{Nd})\s*(\p{Math})\s*(\w)$"
+  let re := regex% r"^\p{Math}\s*(.(?<=\()([a-z])[^,]+),\s*(\p{Nd})\s*(\p{Math})\s*\2$"
   let captures := Regex.captures "∀ (n : Nat), 0 ≤ n" re
   IO.println s!"{captures}"
 
@@ -283,16 +106,16 @@ Output is
 fullMatch: '∀ (n : Nat), 0 ≤ n', 0, 22
-groups: #[(some ('(n : Nat)', 4, 13)), (some ('0', 15, 16)), (some ('≤', 17, 20)), (some ('n', 21, 22))]
+groups: #[(some ('(n : Nat)', 4, 13)), (some ('n', 5, 6)),
+          (some ('0', 15, 16)), (some ('≤', 17, 20))]
 
Components of regular expression: -- *^* : Assertion Start of line - *\p{Math}* : match all characters with the Math property -- *\s\** : match white space -- *(\w)* : capturing group of word characters +- *(?<=\\()* : lookbehind of char '(' - *(\p{Nd})* : capturing group of numeric characters +- *\2* : backreference to second capturing group ## Performance diff --git a/Regex/Backtrack.lean b/Regex/Backtrack.lean index 73dcee8..6e7be29 100644 --- a/Regex/Backtrack.lean +++ b/Regex/Backtrack.lean @@ -2,10 +2,11 @@ import Regex.Syntax.Hir import Regex.Nfa import Regex.Compiler import Regex.Utils +import Regex.Data.Array.Basic import Lean.Util import Init.Core -import Std.Data.Nat.Lemmas -import Std.Tactic.Exact +import Batteries.Data.Nat.Lemmas +import Batteries.Tactic.Exact /-! ## BoundedBacktracker @@ -80,6 +81,12 @@ def create (s : Substring) («at» : String.Pos) : CharPos := let prev? := if «at» = 0 then none else get? s (s.prev «at») ⟨s, «at», get? s «at», prev?⟩ +def prevOf (offset : Nat) (cp : CharPos) : Option CharPos := + if offset ≤ cp.pos.byteIdx then + let pos := cp.s.prevn offset cp.pos + some (create cp.s pos) + else none + /-- to next position CharPos of `cp` -/ def next (cp : CharPos) : CharPos := if cp.pos >= cp.s.stopPos then cp @@ -105,7 +112,7 @@ inductive Frame (n : Nat) where /-- Look for a match starting at `sid` and the given position in the haystack. -/ | Step (sid: Fin n) («at»: CharPos) : Frame n /-- Reset the given `slot` to the given `offset` (which might be `None`). -/ - | RestoreCapture (slot: Nat) (offset: Option String.Pos) : Frame n + | RestoreCapture (slot: Nat) (offset: Nat × Nat × Option String.Pos) : Frame n instance : ToString $ Frame n where toString frame := @@ -183,7 +190,7 @@ abbrev Visited := Array UInt8 /-- position in input string -/ «at» : CharPos /-- slots, positions of captures in haystack -/ - slots: Array (Option String.Pos) + slots: Array (Nat × Nat × (Option String.Pos)) /-- is logging enabled -/ logEnabled : Bool /-- log msgs -/ @@ -198,10 +205,15 @@ namespace SearchState /-- create the SearchState from an NFA -/ def fromNfa (nfa : Checked.NFA) (input : Substring) («at» : String.Pos) (logEnabled : Bool) (h : 0 < nfa.n) : SearchState nfa.n := - let slots : Array (Option String.Pos) := + let slotIdxs : Array (Nat × Nat) := nfa.states - |> Array.filter (fun s => match s with | Checked.State.Capture _ _ _ _ => true | _ => false) - |> Array.map (fun _ => none) + |> Array.filterMap (fun s => + match s with + | Checked.State.Capture _ _ g s => some (s, g) + | _ => none) + let sorted := Array.qsort slotIdxs (fun (a, _) (b, _) => a < b) |> Array.unique + let slots : Array (Nat × Nat × (Option String.Pos)) := + sorted |> Array.map (fun (g, s) => (g, s, none)) { stack := default visited := Array.Ref.mkRef <| @@ -270,6 +282,22 @@ theorem checkVisited'_true_eq (s : SearchState n) (h : checkVisited' s = (true, end Visited +/-- build pairs of subsequent slots -/ +private def toPairs (slots : Array (Nat × Nat × Option String.Pos)) + : Array (Option (String.Pos × String.Pos)) := + if slots.size % 2 = 0 + then + let arr : Array (Option (String.Pos × String.Pos)) := slots.foldl (init := #[]) + fun acc (i, _) => + if i % 2 = 0 then acc + else + match slots.get? (i - 1), slots.get? (i) with + | some (_, _, some v0), some (_, _, some v1) => acc.push (some (v0,v1)) + | some (_, _, none), some (_, _, none) => acc.push none + | _, _ => acc + arr + else #[] + /-- add a msg to the SearchState while doing backtracking. -/ @[inline] private def withMsg (msg : Unit -> String) (state : SearchState n) : SearchState n := if state.logEnabled then { state with msgs := state.msgs.push s!"{msg ()}"} @@ -342,28 +370,65 @@ private def encodeChar? (c: Option Char) : String := @[inline] private def step_empty (next : Fin n) (state : SearchState n) : SearchState n := withMsg (fun _ => s!"{state.sid}: Empty -> {next}") {state with sid := next} +@[inline] private def step_next_char (offset : Nat) (next : Fin n) (state : SearchState n) : SearchState n := + match state.at.prevOf offset with + | some pos => + withMsg (fun _ => s!"{state.sid}: NextChar offset {offset} to charpos {pos} -> {next}") {state with sid := next, «at» := pos} + | none => + withMsg (fun _ => s!"{state.sid}: NextChar offset {offset} failed at charpos {state.at}") state + +@[inline] private def step_fail (state : SearchState n) : SearchState n := + withMsg (fun _ => s!"{state.sid}: Fail") state + +@[inline] private def step_change_frame_step (f t : Fin n) (state : SearchState n) : SearchState n := + let stack := state.stack |> List.dropWhile (fun s => match s with | .Step f' _ => f != f' | _ => true) + match stack with + | .Step _ «at» :: stack' => + let stack := Frame.Step t «at» :: stack' + withMsg (fun _ => s!"{state.sid}: ChangeFrameStep stack {stack}") {state with stack := stack} + | _ => + withMsg (fun _ => s!"{state.sid}: ChangeFrameStep failed ") state + +@[inline] private def step_remove_frame_step (sid : Fin n) (state : SearchState n) : SearchState n := + let stack := state.stack |> List.dropWhile (fun s => match s with | .Step f' _ => sid != f' | _ => true) + match stack with + | .Step _ _ :: stack' => + withMsg (fun _ => s!"{state.sid}: RemoveFrameStep stack {stack'}") {state with stack := stack'} + | _ => + withMsg (fun _ => s!"{state.sid}: RemoveFrameStep failed ") state + @[inline] private def step_look (look : Look) (next : Fin n) (state : SearchState n) : SearchState n := match look with | .Start => if state.at.atStart then - let state := (withMsg (fun _ => s!"Look.Start -> {next}") {state with sid := next}) + let state := (withMsg (fun _ => s!"{state.sid}: Look.Start -> {next}") {state with sid := next}) state else state | .End => if state.at.atStop then - let state := (withMsg (fun _ => s!"Look.End -> {next}") {state with sid := next}) + let state := (withMsg (fun _ => s!"{state.sid}: Look.End -> {next}") {state with sid := next}) state else state + | .EndWithOptionalLF => + if state.at.atStop then + let state := (withMsg (fun _ => s!"{state.sid}: Look.EndWithOptionalLF -> {next}") {state with sid := next}) + state + else + match (state.at.curr?, state.at.next.atStop) with + | (some '\n', true) => + let state := (withMsg (fun _ => s!"{state.sid}: Look.EndWithOptionalLF -> {next}") {state with sid := next}) + state + | _ => (withMsg (fun _ => s!"{state.sid}: Look.EndWithOptionalLF failed at pos {state.at} atStop {state.at.next.atStop}") state) | .StartLF => if state.at.atStart || state.at.prev?.any (· = '\n') then - (withMsg (fun _ => s!"Look.StartLF -> {next}") {state with sid := next}) + (withMsg (fun _ => s!"{state.sid}: Look.StartLF -> {next}") {state with sid := next}) else let prev := encodeChar? state.at.prev? - (withMsg (fun _ => s!"StartLF failed at pos {state.at.pos} prev '{prev}'") state) + (withMsg (fun _ => s!"{state.sid}: StartLF failed at pos {state.at.pos} prev '{prev}'") state) | .EndLF => if state.at.atStop || state.at.curr?.any (· = '\n') then - (withMsg (fun _ => s!"Look.EndLF -> {next}") {state with sid := next}) + (withMsg (fun _ => s!"{state.sid}: Look.EndLF -> {next}") {state with sid := next}) else state | .StartCRLF => if state.at.atStart @@ -371,7 +436,7 @@ private def encodeChar? (c: Option Char) : String := || (state.at.prev?.any (· = '\r') && (state.at.atStop || state.at.curr?.any (· != '\n'))) then - (withMsg (fun _ => s!"Look.StartCRLF -> {next}") {state with sid := next}) + (withMsg (fun _ => s!"{state.sid}: Look.StartCRLF -> {next}") {state with sid := next}) else state | .EndCRLF => if state.at.atStop @@ -379,11 +444,11 @@ private def encodeChar? (c: Option Char) : String := || state.at.curr?.any (· = '\n') && (state.at.pos.byteIdx = 0 || state.at.prev?.any (· != '\r')) then - (withMsg (fun _ => s!"Look.EndCRLF -> {next}") {state with sid := next}) + (withMsg (fun _ => s!"{state.sid}: Look.EndCRLF -> {next}") {state with sid := next}) else state | .WordUnicode => if is_word_unicode state then - (withMsg (fun _ => s!"Look.WordUnicode -> {next}") {state with sid := next}) + (withMsg (fun _ => s!"{state.sid}: Look.WordUnicode -> {next}") {state with sid := next}) else let prev := encodeChar? state.at.prev? let curr := encodeChar? state.at.curr? @@ -391,29 +456,29 @@ private def encodeChar? (c: Option Char) : String := (fun _ => s!"WordUnicode failed at pos {state.at.pos} prev '{prev}' curr '{curr}'") state) | .WordUnicodeNegate => if is_word_unicode_negate state then - let state := (withMsg (fun _ => s!"Look.WordUnicodeNegate -> {next}") {state with sid := next}) + let state := (withMsg (fun _ => s!"{state.sid}: Look.WordUnicodeNegate -> {next}") {state with sid := next}) state else state | .WordStartUnicode => if is_word_start_unicode state then - let state := (withMsg (fun _ => s!"Look.WordStartUnicode -> {next}") {state with sid := next}) + let state := (withMsg (fun _ => s!"{state.sid}: Look.WordStartUnicode -> {next}") {state with sid := next}) state else state | .WordEndUnicode => if is_word_end_unicode state then - let state := (withMsg (fun _ => s!"Look.WordEndUnicode -> {next}") {state with sid := next}) + let state := (withMsg (fun _ => s!"{state.sid}: Look.WordEndUnicode -> {next}") {state with sid := next}) state else state | .WordStartHalfUnicode => if is_word_start_half_unicode state then let state := (withMsg - (fun _ => s!"Look.WordStartHalfUnicode -> {next}") {state with sid := next}) + (fun _ => s!"{state.sid}: Look.WordStartHalfUnicode -> {next}") {state with sid := next}) state else state | .WordEndHalfUnicode => if is_word_end_half_unicode state then let state := (withMsg - (fun _ => s!"Look.WordEndHalfUnicode -> {next}") {state with sid := next}) + (fun _ => s!"{state.sid}: Look.WordEndHalfUnicode -> {next}") {state with sid := next}) state else state @@ -422,11 +487,47 @@ private def encodeChar? (c: Option Char) : String := if state.at.atStop then state else if state.at.curr?.any (Checked.Transition.matches trans) then let next := state.at.next - (withMsg (fun _ => s!"{state.sid}: ByteRange charpos {next} -> {trans.next}") + (withMsg (fun _ => s!"{state.sid}: ByteRange '{encodeChar? state.at.curr?}' matched at charpos {state.at} -> {trans.next}") {state with sid := trans.next, «at» := next}) else (withMsg (fun _ => - s!"{state.sid}: ByteRange failed with '{encodeChar? state.at.curr?}' at charpos {state.at}") + s!"{state.sid}: ByteRange '{encodeChar? state.at.curr?}' failed at charpos {state.at}") + state) + +@[inline] private def step_backreference_loop (s : String) (i : Nat) (case_insensitive : Bool) (cp : CharPos) + : Option CharPos := + if i < s.length + then + if cp.atStop then none else + let c := s.get ⟨i⟩ + let cf := if case_insensitive + then + match Unicode.case_fold_char c with + | #[⟨(cU, _), _⟩, ⟨(cL, _), _⟩] => if cU = c then cL else cU + | _ => c + else c + if cp.curr?.any (fun x => x = c || x = cf) + then step_backreference_loop s (i + 1) case_insensitive cp.next + else none + else some cp + +@[inline] private def step_backreference (b : Nat) (case_insensitive : Bool) (next : Fin n) (state : SearchState n) + : SearchState n := + let slots := state.slots.filter (fun (_, g, _) => g = b) + match slots with + | #[(_, _, some f), (_, _, some t)] => + let s := state.input.extract f t |>.toString + match step_backreference_loop s 0 case_insensitive state.at with + | some cp => + (withMsg (fun _ => s!"{state.sid}: Backreference {b} '{s}' matched from charpos {state.at} to {cp} -> {next}") + {state with sid := next, «at» := cp}) + | none => + (withMsg (fun _ => + s!"{state.sid}: Backreference '{b}' failed at charpos {state.at}, no match with '{s}'") + state) + | _ => + (withMsg (fun _ => + s!"{state.sid}: Backreference '{b}' failed at charpos {state.at}, slot not found") state) @[inline] private def step_sparse_transitions (_ : Checked.NFA) @@ -437,12 +538,12 @@ private def encodeChar? (c: Option Char) : String := (fun trans => state.at.curr?.any (Checked.Transition.matches trans)) with | some t => let next := state.at.next - (withMsg (fun _ => s!"{state.sid}: SparseTransitions charpos {next} -> {t.next}") + (withMsg (fun _ => s!"{state.sid}: SparseTransitions '{encodeChar? state.at.curr?}' matched at charpos {state.at} -> {t.next}") {state with sid := t.next, «at» := next}) | none => (withMsg (fun _ => - s!"{state.sid}: SparseTransitions failed with '{encodeChar? state.at.curr?}'") state) + s!"{state.sid}: SparseTransitions '{encodeChar? state.at.curr?}' failed") state) @[inline] private def step_union (alts : Array $ Fin n) (state : SearchState n) : SearchState n := match alts with @@ -482,15 +583,28 @@ private def encodeChar? (c: Option Char) : String := (withMsg (fun _ => s!"BinaryUnion {state.sid} -> {alt1}") {state with sid := alt1, stack := Stack.push state.stack (Frame.Step alt2 state.at)}) +@[inline] private def step_change_capture_slot (next : Fin n) (slot : Nat) + (state : SearchState n) : SearchState n := + if h : slot < state.slots.size + then + let (s, g, _) := state.slots.get ⟨slot, h⟩ + let slots := state.slots.set ⟨slot, h⟩ (s, g, some state.at.pos) + (withMsg (fun _ => s!"{state.sid}: ChangeCaptureSlot slot {slot} slots {slots} -> {next}") + {state with sid := next, slots := slots }) + else + (withMsg (fun _ => s!"{state.sid}: ChangeCaptureSlot slot {slot} invalid") + state) + @[inline] private def step_capture (next : Fin n) (slot : Nat) (state : SearchState n) : SearchState n := let (stack, slots) := if h : slot < state.slots.size then + let (s, g, _) := state.slots.get ⟨slot, h⟩ let frame := Frame.RestoreCapture slot (state.slots.get ⟨slot, h⟩) - (Stack.push state.stack frame, state.slots.set ⟨slot, h⟩ state.at.pos) + (Stack.push state.stack frame, state.slots.set ⟨slot, h⟩ (s, g, state.at.pos)) else (state.stack, state.slots) - (withMsg (fun _ => s!"{state.sid}: Capture stack {stack} -> {next}") + (withMsg (fun _ => s!"{state.sid}: Capture stack {stack} slots {slots} -> {next}") {state with sid := next, slots := slots, stack := stack }) @[inline] private def step_match (pattern_id : PatternID) @@ -503,7 +617,12 @@ private def encodeChar? (c: Option Char) : String := (searchState : SearchState n) : SearchState n := match state with | .Empty next => step_empty next searchState + | .NextChar offset next => step_next_char offset next searchState + | .Fail => step_fail searchState + | .ChangeFrameStep f t => step_change_frame_step f t searchState + | .RemoveFrameStep s => step_remove_frame_step s searchState | .Look look next => step_look look next searchState + | .BackRef b f next => step_backreference b f next searchState | .ByteRange t => step_byterange t searchState | .SparseTransitions transitions => step_sparse_transitions nfa transitions searchState | .Union alts => step_union alts searchState @@ -628,7 +747,7 @@ theorem steps_lt_or_eq_lt (nfa : Checked.NFA) (s s1 : SearchState nfa.n) (h : st (true, {state' with msgs := if state'.logEnabled - then state'.msgs.push s!"{state'.sid}: backtrackLoop with stack {state'.stack}" + then state'.msgs.push s!"{state'.sid}: Backtrack.Loop stack {state'.stack}" else state'.msgs}) theorem toNextFrameStep_true_lt_or_eq_lt (nfa : Checked.NFA) (s s1 : SearchState nfa.n) @@ -651,16 +770,16 @@ theorem toNextFrameStep_true_lt_or_eq_lt (nfa : Checked.NFA) (s s1 : SearchState rw [hs] at hx simp_all -@[inline] private def toNextFrameRestoreCapture (slot : Nat) (offset : Option String.Pos) +@[inline] private def toNextFrameRestoreCapture (slot : Nat) (offset : ℕ × ℕ × Option String.Pos) (stack : Stack n) (state : SearchState n) : Bool × SearchState n := if h : slot < state.slots.size then let state := {state with slots := state.slots.set ⟨slot,h⟩ offset, stack := stack} - let state := (withMsg (fun _ => s!"{state.sid}: RestoreCapture slots stack {stack}") state) + let state := (withMsg (fun _ => s!"{state.sid}: RestoreCapture stack {stack} slots {state.slots}") state) (true, state) else (false, state) -theorem toNextFrameRestoreCapture_true_lt_or_eq_lt (slot : Nat) (offset : Option String.Pos) +theorem toNextFrameRestoreCapture_true_lt_or_eq_lt (slot : Nat) (offset : ℕ × ℕ × Option String.Pos) (stack : Stack n) (s : SearchState n) (h : toNextFrameRestoreCapture slot offset stack s = (true, s1)) : s.countVisited = s1.countVisited ∧ stack = s1.stack := by @@ -791,23 +910,6 @@ decreasing_by · simp [Nat.le_of_eq h1.left] · simp_all [h1.right] -/-- build pairs of subsequent slots -/ -private def toPairs (slots : Array (Option String.Pos)) - : Array (Option (String.Pos × String.Pos)) := - if slots.size % 2 = 0 - then - let slotsIdx := Array.mapIdx slots (fun i v => (i, v)) - let arr : Array (Option (String.Pos × String.Pos)) := slotsIdx.foldl (init := #[]) - fun acc (i, _) => - if i.val % 2 = 0 then acc - else - match slots.get? (i.val - 1), slots.get? (i.val) with - | some (some v0), some (some v1) => acc.push (some (v0,v1)) - | some none, some none => acc.push none - | _, _ => acc - arr - else #[] - private def dropLastWhile (arr : Array α) (p : α -> Bool) : Array α := arr |> Array.foldr (init := #[]) fun a acc => if acc.size = 0 && p a then acc diff --git a/Regex/Compiler.lean b/Regex/Compiler.lean index cb41b91..fcc7dfa 100644 --- a/Regex/Compiler.lean +++ b/Regex/Compiler.lean @@ -1,4 +1,4 @@ -import Std.Data.Array.Basic +import Batteries.Data.Array.Basic import Regex.Syntax.Hir import Regex.Nfa @@ -43,7 +43,15 @@ private def patch («from» «to» : Unchecked.StateID) : CompilerM PUnit := do then match states.get ⟨«from», h⟩ with | .Empty _ => set (states.set ⟨«from», h⟩ (Unchecked.State.Empty «to»)) + | .NextChar offset _ => set (states.set ⟨«from», h⟩ (Unchecked.State.NextChar offset «to»)) + | .Fail => Except.error s!"patch states .Fail unexpected" + | .ChangeFrameStep f t => + if f = 0 then set (states.set ⟨«from», h⟩ (Unchecked.State.ChangeFrameStep «to» t)) + else if t = 0 then set (states.set ⟨«from», h⟩ (Unchecked.State.ChangeFrameStep f «to»)) + else Except.error "patch states, .ChangeFrameStep from and to not null" + | .RemoveFrameStep _ => set (states.set ⟨«from», h⟩ (Unchecked.State.RemoveFrameStep «to»)) | .Look look _ => set (states.set ⟨«from», h⟩ (Unchecked.State.Look look «to»)) + | .BackRef b f _ => set (states.set ⟨«from», h⟩ (Unchecked.State.BackRef b f «to»)) | .ByteRange t => set (states.set ⟨«from», h⟩ (Unchecked.State.ByteRange {t with «next» := «to»})) | .Capture _ pattern_id group_index slot => @@ -79,6 +87,9 @@ private def add_union : CompilerM Unchecked.StateID := private def add_union_reverse : CompilerM Unchecked.StateID := push (Unchecked.State.UnionReverse #[]) +private def add_backrefence (case_insensitive : Bool) (b : Nat) : CompilerM Unchecked.StateID := + push (Unchecked.State.BackRef b case_insensitive 0) + private def c_range (start «end» : UInt32) : CompilerM ThompsonRef := let trans: Unchecked.Transition := ⟨start, «end», 0⟩ push' (Unchecked.State.ByteRange trans) @@ -86,6 +97,18 @@ private def c_range (start «end» : UInt32) : CompilerM ThompsonRef := private def add_empty : CompilerM Unchecked.StateID := push (Unchecked.State.Empty 0) +private def add_fail : CompilerM Unchecked.StateID := + push (Unchecked.State.Fail) + +private def add_change_state : CompilerM Unchecked.StateID := + push (Unchecked.State.ChangeFrameStep 0 0) + +private def add_remove_state : CompilerM Unchecked.StateID := + push (Unchecked.State.RemoveFrameStep 0) + +private def add_next_char (offset : Nat) : CompilerM Unchecked.StateID := + push (Unchecked.State.NextChar offset 0) + private def c_empty : CompilerM ThompsonRef := push' (Unchecked.State.Empty 0) @@ -105,6 +128,7 @@ private def c_literal (c : Char) : CompilerM ThompsonRef := private def c_look : Syntax.Look -> CompilerM ThompsonRef | .Start => push' (Unchecked.State.Look NFA.Look.Start 0) | .End => push' (Unchecked.State.Look NFA.Look.End 0) + | .EndWithOptionalLF => push' (Unchecked.State.Look NFA.Look.EndWithOptionalLF 0) | .StartLF => push' (Unchecked.State.Look NFA.Look.StartLF 0) | .EndLF => push' (Unchecked.State.Look NFA.Look.EndLF 0) | .StartCRLF => push' (Unchecked.State.Look NFA.Look.StartCRLF 0) @@ -239,6 +263,69 @@ private def c_bounded (hir : Hir) (min max : Nat) (greedy : Bool) (h : min ≤ m else c_empty termination_by sizeOf hir + sizeOf min + sizeOf max +private def c_back_ref (case_insensitive : Bool) (n : Nat) : CompilerM ThompsonRef := do + let backrefence ← add_backrefence case_insensitive n + let empty ← add_empty + patch backrefence empty + pure ⟨backrefence, empty⟩ + +private def c_lookaround (look : Lookaround) : CompilerM ThompsonRef := do + match look with + | .PositiveLookahead h => + let compiled ← c h + let change_state ← add_change_state + let fail ← add_fail + let union ← add_union + let «end» ← add_empty + + patch compiled.end change_state + patch union compiled.start + patch change_state fail + patch change_state «end» + patch union fail + + pure ⟨union, «end»⟩ + | .NegativeLookahead h => + let compiled ← c h + let remove_state ← add_remove_state + let empty ← add_empty + let union ← add_union + let «end» ← add_empty + + patch compiled.end remove_state + patch remove_state empty + patch union compiled.start + patch empty «end» + patch union empty + + pure ⟨union, «end»⟩ + | .PositiveLookbehind length h => + let next_char ← add_next_char length + let compiled ← c h + let «end» ← add_empty + + patch next_char compiled.start + patch compiled.end «end» + + pure ⟨next_char, «end»⟩ + | .NegativeLookbehind length h => + let next_char ← add_next_char length + let compiled ← c h + let remove_state ← add_remove_state + let empty ← add_empty + let union ← add_union + let «end» ← add_empty + + patch next_char compiled.start + patch compiled.end remove_state + patch remove_state empty + patch union next_char + patch empty «end» + patch union empty + + pure ⟨union, «end»⟩ +termination_by sizeOf look + private def c_repetition (rep : Repetition) : CompilerM ThompsonRef := do match rep with | .mk 0 (some 1) greedy h => do @@ -273,6 +360,10 @@ private def c (hir : Hir) : CompilerM ThompsonRef := | .Literal c => c_literal c | .Class (.Unicode cls) => c_unicode_class cls | .Look look => c_look look + | .Lookaround look => + have : sizeOf look < sizeOf hir.kind := by simp [h] + c_lookaround look + | .BackRef f n => c_back_ref f n | .Repetition rep => have : sizeOf rep < sizeOf hir.kind := by simp [h] c_repetition rep diff --git a/Regex/Data/Array/Basic.lean b/Regex/Data/Array/Basic.lean index 5d84655..42bad6a 100644 --- a/Regex/Data/Array/Basic.lean +++ b/Regex/Data/Array/Basic.lean @@ -17,3 +17,15 @@ def last? (a : Array α) : Option α := if h : 0 < a.data.length then a.data.get ⟨a.data.length - 1, Nat.sub_lt h Nat.one_pos⟩ else none + +/-- unique array of sorted array -/ +def unique [BEq α] (intervals: Array α) : Array α := + match intervals.data with + | [] => #[] + | [r] => #[r] + | head :: tail => + let (_, unique) := tail |> List.foldl (init := (head, #[head])) + (fun (prev, unique) r => + if prev == r then (r, unique) + else (r, unique.push r)) + unique diff --git a/Regex/Data/Array/Lemmas.lean b/Regex/Data/Array/Lemmas.lean index d21b395..2b14bf5 100644 --- a/Regex/Data/Array/Lemmas.lean +++ b/Regex/Data/Array/Lemmas.lean @@ -1,4 +1,4 @@ -import Std.Data.Nat.Lemmas +import Batteries.Data.Nat.Lemmas import Init.Data.List.Lemmas import Init.Data.Array.Mem diff --git a/Regex/Data/Char/Basic.lean b/Regex/Data/Char/Basic.lean index c67caaf..4e07e50 100644 --- a/Regex/Data/Char/Basic.lean +++ b/Regex/Data/Char/Basic.lean @@ -1,4 +1,4 @@ -import Std.Data.Nat.Lemmas +import Batteries.Data.Nat.Lemmas import Regex.Data.UInt.Basic namespace Char diff --git a/Regex/Data/Fin/Basic.lean b/Regex/Data/Fin/Basic.lean index f202648..ade9b98 100644 --- a/Regex/Data/Fin/Basic.lean +++ b/Regex/Data/Fin/Basic.lean @@ -1,4 +1,4 @@ -import Std.Data.Fin.Lemmas +import Batteries.Data.Fin.Lemmas namespace Fin diff --git a/Regex/Data/List/Lemmas.lean b/Regex/Data/List/Lemmas.lean index 8a768a8..4281302 100644 --- a/Regex/Data/List/Lemmas.lean +++ b/Regex/Data/List/Lemmas.lean @@ -1,8 +1,8 @@ -import Std.Data.Nat.Lemmas -import Std.Data.Fin.Lemmas -import Std.Data.Int.Lemmas -import Std.Data.List.Basic -import Std.Data.List.Lemmas +import Batteries.Data.Nat.Lemmas +import Batteries.Data.Fin.Lemmas +import Batteries.Data.Int.Lemmas +import Batteries.Data.List.Basic +import Batteries.Data.List.Lemmas import Regex.Data.Nat.Basic diff --git a/Regex/Data/Nat/Basic.lean b/Regex/Data/Nat/Basic.lean index f373aaa..66511ca 100644 --- a/Regex/Data/Nat/Basic.lean +++ b/Regex/Data/Nat/Basic.lean @@ -1,4 +1,4 @@ -import Std.Data.Nat.Lemmas +import Batteries.Data.Nat.Lemmas namespace Nat diff --git a/Regex/Data/UInt/Basic.lean b/Regex/Data/UInt/Basic.lean index 05adfc6..5aa3f92 100644 --- a/Regex/Data/UInt/Basic.lean +++ b/Regex/Data/UInt/Basic.lean @@ -1,5 +1,5 @@ -import Std.Data.Fin.Lemmas -import Std.Data.Nat.Lemmas +import Batteries.Data.Fin.Lemmas +import Batteries.Data.Nat.Lemmas import Regex.Data.Fin.Basic import Regex.Data.Nat.Basic diff --git a/Regex/Interval/Basic.lean b/Regex/Interval/Basic.lean index 2e950b8..dd37ce3 100644 --- a/Regex/Interval/Basic.lean +++ b/Regex/Interval/Basic.lean @@ -1,9 +1,9 @@ import Init.Data.Ord -import Std.Logic -import Std.Data.Nat.Lemmas -import Std.Data.Fin.Lemmas -import Std.Data.Int.Lemmas -import Std.Data.List.Basic +import Batteries.Logic +import Batteries.Data.Nat.Lemmas +import Batteries.Data.Fin.Lemmas +import Batteries.Data.Int.Lemmas +import Batteries.Data.List.Basic import Mathlib.Order.BoundedOrder import Mathlib.Order.Interval.Basic import Regex.Utils diff --git a/Regex/Interval/Lemmas.lean b/Regex/Interval/Lemmas.lean index 026edb6..e0f9881 100644 --- a/Regex/Interval/Lemmas.lean +++ b/Regex/Interval/Lemmas.lean @@ -1,10 +1,10 @@ import Init.Data.Ord -import Std.Logic -import Std.Data.Nat.Lemmas -import Std.Data.Fin.Lemmas -import Std.Data.Int.Lemmas -import Std.Data.List.Basic -import Std.Data.Array.Lemmas +import Batteries.Logic +import Batteries.Data.Nat.Lemmas +import Batteries.Data.Fin.Lemmas +import Batteries.Data.Int.Lemmas +import Batteries.Data.List.Basic +import Batteries.Data.Array.Lemmas import Mathlib.Data.List.Chain import Mathlib.Order.BoundedOrder import Mathlib.Order.Interval.Basic diff --git a/Regex/Nfa.lean b/Regex/Nfa.lean index 91f4c5c..d3b78c4 100644 --- a/Regex/Nfa.lean +++ b/Regex/Nfa.lean @@ -1,4 +1,4 @@ -import Std.Data.Fin.Basic +import Batteries.Data.Fin.Basic import Regex.Utils namespace NFA @@ -20,6 +20,8 @@ inductive Look where | Start : Look /-- Match the end of text. -/ | End : Look + /-- Match the end of text (before optional newline). -/ + | EndWithOptionalLF : Look /-- Match the beginning of a line or the beginning of text. -/ | StartLF : Look /-- Match of a line or the end of text. -/ @@ -45,6 +47,7 @@ namespace Look def toString : Look -> String | .Start => s!"Start" | .End => s!"End" + | .EndWithOptionalLF => s!"EndWithOptionalLF" | .StartLF => s!"StartLF" | .EndLF => s!"EndLF" | .StartCRLF => s!"StartCRLF" @@ -91,6 +94,17 @@ inductive State where /-- An empty state whose only purpose is to forward the automaton to another state via an unconditional epsilon transition. -/ | Empty (next: StateID) : State + /-- use netx char -/ + | NextChar (offset : Nat) (next: StateID) : State + /-- Fail, force backtrack -/ + | Fail : State + /-- change Frame.Step in stack and force backtrack -/ + | ChangeFrameStep («from» to: StateID) : State + /-- remove Frame.Step in stack and force backtrack -/ + | RemoveFrameStep (sid : StateID) : State + /-- A state with a single transition may only be followed if the currunt chars match the + backrefence to the capturung group. -/ + | BackRef (n : Nat) (case_insensitive : Bool) (sid : StateID) : State /-- A state with a single transition that can only be taken if the current input symbol is in a particular range of chars. -/ | ByteRange (trans : Transition) : State @@ -120,6 +134,12 @@ namespace State def toString : State -> String | .Empty next => s!"Empty => {next}" + | .NextChar offset next => s!"NextChar offset {offset} => {next}" + | .Fail => s!"Fail" + | .ChangeFrameStep «from» to => s!"ChangeFrameStep from {«from»} to {to}" + | .RemoveFrameStep sid => s!"RemoveFrameStep {sid}" + | .BackRef b f sid => + s!"backreference {b} {if f then "case_insensitive" else ""} => {sid}" | .ByteRange trans => s!"byte-range {UInt32.intAsString trans.start}-{UInt32.intAsString trans.end} => {trans.next}" | .SparseTransitions trans => @@ -192,6 +212,17 @@ inductive State (n : Nat) where /-- An empty state whose only purpose is to forward the automaton to another state via an unconditional epsilon transition. -/ | Empty (next: Fin n) : State n + /-- use netx char -/ + | NextChar (offset : Nat) (next: Fin n) : State n + /-- Fail, force backtracking -/ + | Fail : State n + /-- change Frame.Step in stack and force backtracking -/ + | ChangeFrameStep (fr to: Fin n) : State n + /-- remove Frame.Step in stack and force backtrack -/ + | RemoveFrameStep (sid : Fin n) : State n + /-- A state with a single transition may only be followed if the currunt chars match the + backrefence to the capturung group. -/ + | BackRef (b : Nat) (case_insensitive : Bool) (sid : Fin n) : State n /-- A state with a single transition that can only be taken if the current input symbol is in a particular range of chars. -/ | ByteRange (trans : Transition n) : State n @@ -233,6 +264,12 @@ namespace State def toString : State n -> String | .Empty next => s!"Empty => {next}" + | .NextChar offset next => s!"NextChar offset {offset} => {next}" + | .Fail => s!"Fail" + | .ChangeFrameStep f t => s!"ChangeFrameStep from {f} to {t}" + | .RemoveFrameStep sid => s!"RemoveFrameStep {sid}" + | .BackRef b f sid => + s!"backreference {b} {if f then "case_insensitive" else ""} => {sid}" | .ByteRange trans => s!"byte-range {Nat.intAsString trans.start}-{Nat.intAsString trans.end} => {trans.next}" | .SparseTransitions trans => @@ -294,6 +331,14 @@ private def toCkeckedTransition? (t : Unchecked.Transition) (n : Nat) private def toCkeckedState? (s : Unchecked.State) (n : Nat) : Option $ Checked.State n := match s with | .Empty next => (toFin? next n) |> Option.map (Checked.State.Empty ·) + | .NextChar offset next => (toFin? next n) |> Option.map (Checked.State.NextChar offset ·) + | .Fail => some Checked.State.Fail + | .ChangeFrameStep f t => + match (toFin? f n), (toFin? t n) with + | some f, some t => some (Checked.State.ChangeFrameStep f t) + |_, _ => none + | .RemoveFrameStep sid => (toFin? sid n) |> Option.map (Checked.State.RemoveFrameStep ·) + | .BackRef b f sid => (toFin? sid n) |> Option.map (Checked.State.BackRef b f ·) | .ByteRange trans => (toCkeckedTransition? trans n) |> Option.map (Checked.State.ByteRange ·) | .SparseTransitions trans => trans diff --git a/Regex/Notation.lean b/Regex/Notation.lean index c9d9856..89495ff 100644 --- a/Regex/Notation.lean +++ b/Regex/Notation.lean @@ -52,6 +52,7 @@ private def mkTermOfLook (l : NFA.Look) : Term := match l with | .Start => Syntax.mkApp (mkCIdent ``NFA.Look.Start) #[] | .End => Syntax.mkApp (mkCIdent ``NFA.Look.End) #[] + | .EndWithOptionalLF => Syntax.mkApp (mkCIdent ``NFA.Look.EndWithOptionalLF) #[] | .StartLF => Syntax.mkApp (mkCIdent ``NFA.Look.StartLF) #[] | .EndLF => Syntax.mkApp (mkCIdent ``NFA.Look.EndLF) #[] | .StartCRLF => Syntax.mkApp (mkCIdent ``NFA.Look.StartCRLF) #[] @@ -70,6 +71,16 @@ private def mkTermOfState (s : NFA.Checked.State n) : Term := match s with | .Empty next => Syntax.mkApp (mkCIdent ``NFA.Checked.State.Empty) #[Quote.quote next] + | .NextChar offset next => + Syntax.mkApp (mkCIdent ``NFA.Checked.State.NextChar) #[Quote.quote offset, Quote.quote next] + | .Fail => + Syntax.mkApp (mkCIdent ``NFA.Checked.State.Fail) #[] + | .ChangeFrameStep f t => + Syntax.mkApp (mkCIdent ``NFA.Checked.State.ChangeFrameStep) #[Quote.quote f, Quote.quote t] + | .RemoveFrameStep s => + Syntax.mkApp (mkCIdent ``NFA.Checked.State.RemoveFrameStep) #[Quote.quote s] + | .BackRef b f sid => + Syntax.mkApp (mkCIdent ``NFA.Checked.State.BackRef) #[Quote.quote b, Quote.quote f, Quote.quote sid] | .ByteRange t => Syntax.mkApp (mkCIdent ``NFA.Checked.State.ByteRange) #[Quote.quote t] | .SparseTransitions transitions => diff --git a/Regex/Regex.lean b/Regex/Regex.lean index 9550d77..cd3882a 100644 --- a/Regex/Regex.lean +++ b/Regex/Regex.lean @@ -53,9 +53,10 @@ instance : ToString Captures where toString c := s!"fullMatch: {c.fullMatch}\ngroups: {c.groups}" /-- Build a Regex from the given pattern. -/ -def build (s : String) (flags : Syntax.Flags := default) (config : Compiler.Config := default) +def build (s : String) (flavor : Syntax.Flavor := default) + (flags : Syntax.Flags := default) (config : Compiler.Config := default) : Except String Regex := do - let nfa ← Syntax.AstItems.parse s >>= Syntax.translate flags >>= Compiler.compile config + let nfa ← Syntax.AstItems.parse s flavor >>= Syntax.translate flags >>= Compiler.compile config Except.ok ⟨nfa⟩ namespace Log diff --git a/Regex/Syntax/Ast/Ast.lean b/Regex/Syntax/Ast/Ast.lean index fa8e6af..cc0f438 100644 --- a/Regex/Syntax/Ast/Ast.lean +++ b/Regex/Syntax/Ast/Ast.lean @@ -1,4 +1,4 @@ -import Std.Data.Array.Basic +import Batteries.Data.Array.Basic import Regex.Utils /-! @@ -11,6 +11,8 @@ namespace Syntax.AstItems /-- The type of an error that occurred while building an AST. -/ inductive ErrorKind + /-- Backrefence invalid. -/ + | BackRefenceInvalid /-- The capturing group limit was exceeded. -/ | CaptureLimitExceeded /-- An invalid escape sequence was found in a character class set. -/ @@ -23,6 +25,8 @@ inductive ErrorKind | ClassUnclosed /-- An invalid decimal number was given where one was expected. -/ | DecimalInvalid + /-- End quote without a corresponding open quote. -/ + | EndQuoteWithoutOpenQuote /-- A bracketed hex literal was empty. -/ | EscapeHexEmpty /-- A bracketed hex literal did not correspond to a Unicode scalar value. -/ @@ -33,6 +37,8 @@ inductive ErrorKind | EscapeUnexpectedEof /-- An unrecognized escape sequence. -/ | EscapeUnrecognized + /-- Fixed width in look behind -/ + | FixedWidtExcpected /-- A dangling negation was used when setting flags, e.g., `i-`. -/ | FlagDanglingNegation /-- A flag was used twice, e.g., `i-i`. -/ @@ -89,17 +95,20 @@ inductive ErrorKind namespace ErrorKind def toString : ErrorKind -> String + | .BackRefenceInvalid => "no capturing group found for backrefence" | .CaptureLimitExceeded => "exceeded the maximum number of capturing groups" | .ClassEscapeInvalid => "invalid escape sequence found in character class" | .ClassRangeInvalid => "invalid character class range, the start must be <= the end" | .ClassRangeLiteral => "invalid range boundary, must be a literal" | .ClassUnclosed => "unclosed character class" | .DecimalInvalid => "decimal literal invalid" + | .EndQuoteWithoutOpenQuote => "end quote without a corresponding open quote" | .EscapeHexEmpty => "hexadecimal literal empty" | .EscapeHexInvalid => "hexadecimal literal is not a Unicode scalar value" | .EscapeHexInvalidDigit => "invalid hexadecimal digit" | .EscapeUnexpectedEof => "incomplete escape sequence, reached end of pattern prematurely" | .EscapeUnrecognized => "unrecognized escape sequence" + | .FixedWidtExcpected => "fixed width expr in look behind expected" | .FlagDanglingNegation => "dangling flag negation operator" | .FlagDuplicate => "duplicate flag" | .FlagRepeatedNegation => "flag negation operator repeated" @@ -145,6 +154,8 @@ def toErrorAt (s : String) (i : Nat) (kind : ErrorKind) (msg : String := "") : S /-- The type of a Unicode hex literal. -/ inductive HexLiteralKind where + /-- A `\x` prefix. When used without brackets, this form is limited to one digit (Pcre flavor). -/ + | x : HexLiteralKind /-- A `\x` prefix. When used without brackets, this form is limited to two digits. -/ | X : HexLiteralKind /-- A `\u` prefix. When used without brackets, this form is limited to four digits. -/ @@ -153,6 +164,7 @@ inductive HexLiteralKind where namespace HexLiteralKind def digits : HexLiteralKind -> Nat + | .x => 1 | .X => 2 | .UnicodeShort => 4 @@ -173,8 +185,10 @@ namespace LiteralKind def toString : LiteralKind -> String | .Verbatim => "Verbatim" + | .Hex .x => "Hex x" | .Hex .X => "Hex X" | .Hex .UnicodeShort => "Hex UnicodeShort" + | .HexBrace .x => "HexBrace x" | .HexBrace .X => "HexBrace X" | .HexBrace .UnicodeShort => "HexBrace UnicodeShort" @@ -205,6 +219,23 @@ end Literal instance : ToString Literal where toString := Literal.toString +/-- A backrefence to a capturung group. -/ +structure BackRef where + /-- The span of this backrefence. -/ + span: Substring + /-- number of the capturung group. -/ + n: Nat + +namespace BackRef + +def toString (br : BackRef) : String := + s!"Backrefence {spanToString br.span} '{br.n}'" + +end BackRef + +instance : ToString BackRef where + toString := BackRef.toString + /-- A range repetition operator.-/ inductive RepetitionRange where /-- `{m}` -/ @@ -348,16 +379,33 @@ structure Flags where instance : ToString Flags where toString flags := s!"Flags {flags.items}" +/-- The kind of a Lookaround. -/ +inductive LookaroundKind where + | PositiveLookahead : LookaroundKind + | NegativeLookahead : LookaroundKind + | PositiveLookbehind : Nat -> LookaroundKind + | NegativeLookbehind : Nat -> LookaroundKind + +instance : ToString LookaroundKind where + toString look := + match look with + |.PositiveLookahead => "PositiveLookahead" + |.NegativeLookahead => "NegativeLookahead" + |.PositiveLookbehind i => s!"PositiveLookbehind Length {i}" + |.NegativeLookbehind i => s!"NegativeLookbehind Length {i}" + /-- The kind of a group. -/ inductive GroupKind where | CaptureIndex : Nat -> GroupKind | NonCapturing : Flags -> GroupKind + | Lookaround : LookaroundKind -> GroupKind namespace GroupKind def toString : GroupKind -> String | .CaptureIndex i => s!"CaptureIndex {i}" | .NonCapturing flags => s!"NonCapturing {flags}" + | .Lookaround kind => s!"Lookaround {kind}" end GroupKind @@ -411,10 +459,14 @@ inductive AssertionKind where | StartLine : AssertionKind /-- `$` -/ | EndLine : AssertionKind + /-- `$` pcre flavor -/ + | EndLineWithOptionalLF : AssertionKind /-- `\A` -/ | StartText : AssertionKind /-- `\z` -/ | EndText : AssertionKind + /-- `\Z` pcre flavor -/ + | EndTextWithOptionalLF : AssertionKind /-- \b -/ | WordBoundary : AssertionKind /-- \B -/ @@ -433,8 +485,10 @@ namespace AssertionKind def toString : AssertionKind -> String | .StartLine => s!"StartLine" | .EndLine => s!"EndLine" + | .EndLineWithOptionalLF => s!"EndLineWithOptionalLF" | .StartText => s!"StartText" | .EndText => s!"EndText" + | .EndTextWithOptionalLF => s!"EndTextWithOptionalLF" | .WordBoundary => s!"WordBoundary" | .NotWordBoundary => s!"NotWordBoundary" | .WordBoundaryStart => s!"WordBoundaryStart" @@ -589,6 +643,7 @@ inductive SetFlags where /-- A primitive is an expression with no sub-expressions. -/ inductive Primitive where | Literal : AstItems.Literal -> Primitive + | BackRef : AstItems.BackRef -> Primitive | Dot : Substring -> Primitive | Assertion : Assertion -> Primitive | Unicode : ClassUnicode -> Primitive @@ -660,6 +715,8 @@ inductive Ast where | Flags : SetFlags -> Ast /-- A single character literal, which includes escape sequences. -/ | Literal : Literal -> Ast + /-- A backrefence to a capturung group. -/ + | BackRef : BackRef -> Ast /-- The "any character" class. -/ | Dot : Substring -> Ast /-- A single zero-width assertion. -/ @@ -747,6 +804,7 @@ namespace Primitive def into_ast (p : Primitive) : Ast := match p with | .Literal lit => Ast.Literal lit + | .BackRef n => Ast.BackRef n | .Dot span => Ast.Dot span | .Assertion a => Ast.Assertion a | .Unicode cls => Ast.ClassUnicode cls @@ -762,6 +820,7 @@ def into_class_set_item (p : Primitive) : Except String ClassSetItem := def into_class_literal (p : Primitive) : Except String Syntax.AstItems.Literal := match p with | .Literal lit => Except.ok lit + | .Perl _ => Except.error "escape sequence unexpected in range" | _ => Except.error "into_class_literal, unexpected entry" end Primitive @@ -879,6 +938,7 @@ def span (ast : Ast) : Substring := | .Empty => default | .Flags ⟨span, _⟩ => span | .Literal lit => lit.span + | .BackRef br => br.span | .Dot span => span | .Assertion ⟨span, _⟩ => span | .ClassUnicode cls => cls.span @@ -896,6 +956,7 @@ def toString (ast : Ast) (col : Nat) : String := | .Empty => s!"Empty" | .Flags ⟨_, flags⟩ => s!"Flags {flags}" | .Literal lit => s!"{lit}" + | .BackRef br => s!"{br}" | .Dot span => s!"Dot {spanToString span}" | .Assertion a => s!"Assertion {a}" | .ClassUnicode cls => s!"ClassUnicode {cls}" diff --git a/Regex/Syntax/Ast/Parse.lean b/Regex/Syntax/Ast/Parse.lean index a010a1e..9e34996 100644 --- a/Regex/Syntax/Ast/Parse.lean +++ b/Regex/Syntax/Ast/Parse.lean @@ -1,8 +1,22 @@ -import Std.Data.Nat.Lemmas +import Batteries.Data.Nat.Lemmas import Regex.Data.Array.Basic import Regex.Syntax.Ast.Ast import Regex.Utils +namespace Syntax + +/-- Flavor of regular expressions -/ +inductive Flavor where + /-- Perl-compatible regular expressions (https://www.pcre.org/current/doc/html). -/ + | Pcre : Flavor + /-- Rust-compatible regular expressions (https://docs.rs/regex/latest/regex/#syntax). -/ + | Rust : Flavor +deriving BEq + +instance : Inhabited Flavor := ⟨Syntax.Flavor.Pcre⟩ + +end Syntax + namespace Syntax.AstItems /-! @@ -59,14 +73,18 @@ private inductive ClassState where private structure Parser where /-- The current capture index. -/ capture_index : Nat + /-- The maximal single digit backreference. -/ + max_backreference : Nat + /-- Disable pattern metacharacters from \Q until \E -/ + disabled_metacharacters : Bool /-- A stack of grouped sub-expressions, including alternations. -/ stack_group: Array GroupState /-- A stack of nested character classes. -/ stack_class: Array ClassState -instance : Inhabited Parser := ⟨0, #[], #[]⟩ +instance : Inhabited Parser := ⟨0, 0, false, #[], #[]⟩ -abbrev ParserM := StateT Parser (Except String) +abbrev ParserM := ReaderT Flavor $ StateT Parser (Except String) /-- Represents the count of parsed chars -/ abbrev NChars := Nat @@ -77,6 +95,9 @@ private def is_hex(c : Char) : Bool := private def is_ascii (c : Char) : Bool := c.val <= 0x7F +private def is_whitespace (c : Char) := + c = ' ' || '\x09' ≤ c && c ≤ '\x0d' + /-- Returns true if the given character has significance in a regex. -/ private def is_meta_character (c: Char) : Bool := match c with @@ -94,6 +115,33 @@ private def is_escapeable_character (c: Char) : Bool := else if c = '<' || c = '>' then false else true +/- todo : check FlagsItemKind.Negation -/ +def is_whitespace_enabled (concat : Concat) : Bool := + Array.any concat.asts (fun ast => + match ast with + | .Flags ⟨_, ⟨_, flags⟩⟩ => + Array.any flags (fun flag => + match flag with + | ⟨_, .Flag .IgnoreWhitespace⟩ => true + | _ => false) + | _ => false) + +private def consume_space (concat : Concat) (pattern : String) (i : Nat) : Nat := + if !is_whitespace_enabled concat then i + else if i >= pattern.length then i + else if is_whitespace (pattern.getAtCodepoint i) + then consume_space concat pattern (i+1) + else i +termination_by pattern.length - i + +theorem consume_space_ge (concat : Concat) (pattern : String) (i : Nat) + : i ≤ consume_space concat pattern i := by + induction i using consume_space.induct concat pattern with + | case1 _ _ => unfold consume_space; split <;> omega + | case2 _ _ _ => unfold consume_space; split <;> omega + | case3 _ _ _ _ => unfold consume_space; split <;> omega + | case4 _ _ _ => unfold consume_space; split <;> omega + /-- Parse a hex representation of any Unicode scalar value. -/ private def parse_hex_brace (pattern : String) (i : Nat) (kind: HexLiteralKind) : Except String (NChars × Literal) := do @@ -124,15 +172,28 @@ private def parse_hex_digits (pattern : String) (i : Nat) (kind: HexLiteralKind) else Except.error (toError pattern .EscapeHexInvalidDigit) else Except.error (toError pattern .EscapeUnexpectedEof) +private def guess_kind (pattern : String) (i : Nat) : HexLiteralKind := + if i + 2 <= pattern.length + then + let c := pattern.getAtCodepoint (i + 2) + if c.isHexDigit then HexLiteralKind.X else HexLiteralKind.x + else HexLiteralKind.x + /-- Parse a hex representation of a Unicode codepoint. -/ private def parse_hex (pattern : String) (i : Nat) - : Except String (NChars × Literal) := do + : ParserM (NChars × Literal) := do + let flavor ← read let kind := match pattern.getAtCodepoint i with - | 'x' => HexLiteralKind.X + | 'x' => guess_kind pattern i | _ => HexLiteralKind.UnicodeShort if pattern.getAtCodepoint (i + 1) = '{' then parse_hex_brace pattern (i + 1) kind - else parse_hex_digits pattern (i + 1) kind + else + if flavor == Flavor.Pcre && 'x' = pattern.getAtCodepoint i && !(pattern.getAtCodepoint (i+1)).isHexDigit + then + let lit : Literal := ⟨String.toSpan pattern (i - 1) (i + 1), LiteralKind.Verbatim, ⟨0, by simp_arith⟩⟩ + pure (0, lit) + else parse_hex_digits pattern (i + 1) kind /-- Attempt to parse an ASCII character class, e.g., `[:alnum:]`. -/ private def maybe_parse_ascii_class (pattern : String) (i : Nat) @@ -173,6 +234,30 @@ private def maybe_parse_special_word_boundary (pattern : String) (i : Nat) else Except.ok none +private def maybe_parse_backref (pattern : String) (i : Nat) + : ParserM $ Option (NChars × BackRef) := do + let state ← get + let c := pattern.getAtCodepoint (i) + let c1 := pattern.getAtCodepoint (i + 1) + let c2 := pattern.getAtCodepoint (i + 2) + if c.isDigit && !c1.isDigit + then + let span := String.toSpan pattern (i - 1) (i) + let n := (c.val - '0'.val).toNat + if 0 = n then pure none + else + if n > state.max_backreference then set {state with max_backreference := n} + + pure (some (1, ⟨span, n⟩)) + else if c.isDigit && c1.isDigit && !c2.isDigit + then + let span := String.toSpan pattern (i - 1) (i) + let n := (c.val - '0'.val).toNat * 10 + (c1.val - '0'.val).toNat + if 0 < n && n ≤ state.capture_index + then pure (some (2, ⟨span, n⟩)) + else pure none + else pure none + /-- Parse a Unicode class in either the single character notation `\pN` or the multi-character bracketed notation `\p{Greek}`. Assumes '\p' is already parsed. -/ @@ -215,8 +300,23 @@ private def parse_perl_class (pattern : String) (i : Nat) : Except String ClassP Except.ok ⟨⟨pattern, ⟨i⟩, ⟨i + 1⟩⟩, kind, neg⟩ +private def parse_control_char (pattern : String) (i : Nat) + : Except String (NatPos × Primitive) := do + let toControl (n : UInt32) : Primitive := + let c : Char := if h : UInt32.isValidChar (n) then ⟨n, h⟩ else ⟨0, by simp_arith⟩ + let lit : Literal := ⟨String.toSpan pattern (i - 1) (i + 1), LiteralKind.Verbatim, c⟩ + Primitive.Literal lit + let c := pattern.getAtCodepoint (i+1) + if c.isUpper then pure (NatPos.succ 1, toControl (c.val - 'A'.val + 1)) + else if c.isLower then pure (NatPos.succ 1, toControl (c.val - 'a'.val + 1)) + else if c.val ≥ 32 && c.val ≤ 64 then pure (NatPos.succ 1, toControl (c.val - 32 + 96)) + else if c.val ≥ 91 && c.val ≤ 96 then pure (NatPos.succ 1, toControl (c.val - 91 + 27)) + else Except.error (toError pattern .EscapeUnrecognized) + /-- Parse an escape sequence as a primitive AST. -/ -private def parse_escape (pattern : String) (i : Nat) : Except String (NatPos × Primitive) := do +private def parse_escape (pattern : String) (i : Nat) (inSetClass : Bool := false) + : ParserM (NatPos × Primitive) := do + let flavor ← read let toVerbatim (c : Char) : Primitive := let lit : Literal := ⟨String.toSpan pattern (i - 1) (i + 1), LiteralKind.Verbatim, c⟩ Primitive.Literal lit @@ -224,43 +324,80 @@ private def parse_escape (pattern : String) (i : Nat) : Except String (NatPos × match c with | 'u' | 'x' => let (n, lit) ← parse_hex pattern i - Except.ok (NatPos.succ n, Primitive.Literal lit) + pure (NatPos.succ n, Primitive.Literal lit) | 'p' | 'P' => let (n, cls) ← parse_unicode_class (c = 'P') pattern (i + 1) - Except.ok (NatPos.succ n, Primitive.Unicode cls) + pure (NatPos.succ n, Primitive.Unicode cls) | 'd' | 's' | 'w' | 'D' | 'S' | 'W' => let cls ← parse_perl_class pattern i - Except.ok (NatPos.succ 0, Primitive.Perl cls) - | 'a' => Except.ok (NatPos.one, toVerbatim '\x07') - | 'f' => Except.ok (NatPos.one, toVerbatim '\x0C') - | 't' => Except.ok (NatPos.one, toVerbatim '\t') - | 'n' => Except.ok (NatPos.one, toVerbatim '\n') - | 'r' => Except.ok (NatPos.one, toVerbatim '\r') - | 'V' => Except.ok (NatPos.one, toVerbatim '\x0B') + pure (NatPos.succ 0, Primitive.Perl cls) + | 'a' => pure (NatPos.one, toVerbatim '\x07') | 'b' => - if '{' = pattern.getAtCodepoint (i + 1) then + if inSetClass then pure (NatPos.one, toVerbatim '\x08') + else if '{' = pattern.getAtCodepoint (i + 1) then match ← maybe_parse_special_word_boundary pattern i with | some (n, kind) => - Except.ok (NatPos.succ n, + pure (NatPos.succ n, Primitive.Assertion ⟨String.toSpan pattern i (i + n + 1), kind⟩) | none => Except.error (toError pattern .EscapeUnrecognized) else - Except.ok (NatPos.succ 0, + pure (NatPos.succ 0, Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.WordBoundary⟩) + | 'c' => + if flavor == Flavor.Pcre + then parse_control_char pattern i + else Except.error (toError pattern .EscapeUnrecognized) + | 'e' => pure (NatPos.one, toVerbatim '\x07') + | 'f' => pure (NatPos.one, toVerbatim '\x0C') + | 't' => pure (NatPos.one, toVerbatim '\t') + | 'n' => pure (NatPos.one, toVerbatim '\n') + | 'r' => pure (NatPos.one, toVerbatim '\r') + | 'V' => pure (NatPos.one, toVerbatim '\x0B') | 'z' => - Except.ok (NatPos.succ 0, + pure (NatPos.succ 0, Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.EndText⟩) | 'A' => - Except.ok (NatPos.succ 0, + pure (NatPos.succ 0, Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.StartText⟩) | 'B' => - Except.ok (NatPos.succ 0, + pure (NatPos.succ 0, Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.NotWordBoundary⟩) + | 'Z' => + pure (NatPos.succ 0, + Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.EndTextWithOptionalLF⟩) | _ => if is_meta_character c - then Except.ok (NatPos.one, toVerbatim c) + then pure (NatPos.one, toVerbatim c) else if is_escapeable_character c - then Except.ok (NatPos.one, toVerbatim c) + then pure (NatPos.one, toVerbatim c) + else if flavor == Flavor.Pcre then + let c1 := pattern.getAtCodepoint (i+1) + let c2 := pattern.getAtCodepoint (i+2) + if c.isDigit && !c1.isDigit + then if inSetClass && '8' ≤ c && c ≤ '9' then pure (NatPos.one, toVerbatim c) else + let n ← Char.decodeOctDigits [c] + if h : isValidChar n + then + let x : AstItems.Literal := ⟨String.toSpan pattern i (i + 1), LiteralKind.Verbatim, ⟨n, h⟩⟩ + pure (NatPos.succ 0, Primitive.Literal x) + else Except.error (toError pattern .EscapeHexInvalid) + else if c.isDigit && c1.isDigit && c2.isDigit + then + let n ← Char.decodeOctDigits [c, c1, c2] + if h : isValidChar n + then + let x : AstItems.Literal := ⟨String.toSpan pattern i (i + 1), LiteralKind.Verbatim, ⟨n, h⟩⟩ + pure (NatPos.succ 2, Primitive.Literal x) + else Except.error (toError pattern .EscapeHexInvalid) + else if c.isDigit && c1.isDigit && !c2.isDigit + then + let n ← Char.decodeOctDigits [c, c1] + if h : isValidChar n + then + let x : AstItems.Literal := ⟨String.toSpan pattern i (i + 1), LiteralKind.Verbatim, ⟨n, h⟩⟩ + pure (NatPos.succ 1, Primitive.Literal x) + else Except.error (toError pattern .EscapeHexInvalid) + else pure (NatPos.one, toVerbatim c) else Except.error (toError pattern .EscapeUnrecognized) /-- Parse a decimal number into a u32 -/ @@ -298,7 +435,7 @@ private def parse_counted_repetition (pattern : String) (i : Nat) (concat : Conc greedy ast )) - Except.ok (1 +(n.val+1)+offset, (Concat.mk (Syntax.AstItems.span ast) asts)) + pure (1 +(n.val+1)+offset, (Concat.mk (Syntax.AstItems.span ast) asts)) else let (m, count_end) ← parse_decimal pattern (i+n.val+1) let c := pattern.getAtCodepoint (i+n.val+1+m.val) @@ -314,7 +451,7 @@ private def parse_counted_repetition (pattern : String) (i : Nat) (concat : Conc greedy ast )) - Except.ok (1 + (n.val+m.val+1+offset), (Concat.mk (Syntax.AstItems.span ast) asts)) + pure (1 + (n.val+m.val+1+offset), (Concat.mk (Syntax.AstItems.span ast) asts)) else Except.error (toError pattern .RepetitionCountUnclosed) else if c = '}' then let c := pattern.getAtCodepoint (i+n.val+1) @@ -328,40 +465,59 @@ private def parse_counted_repetition (pattern : String) (i : Nat) (concat : Conc greedy ast )) - Except.ok (1 + n.val+offset, (Concat.mk (Syntax.AstItems.span ast) asts)) + pure (1 + n.val+offset, (Concat.mk (Syntax.AstItems.span ast) asts)) else Except.error (toError pattern .RepetitionCountUnclosed) | none => Except.error (toErrorAt pattern i .RepetitionMissing) /-- Parse a single item in a character class as a primitive -/ private def parse_set_class_item (pattern : String) (i : Nat) - : Except String (NatPos × Primitive) := do + : ParserM (NatPos × Option Primitive) := do + let flavor ← read + let state ← get let c := pattern.getAtCodepoint i match c with | '\\' => - let (⟨n, _⟩ , p) ← parse_escape pattern (i + 1) - Except.ok (NatPos.succ n, p) + let c1 := pattern.getAtCodepoint (i + 1) + if flavor == Flavor.Pcre && c1 = 'Q' + then + set {state with disabled_metacharacters := true} + pure (⟨2, by simp⟩ , none) + else if flavor == Flavor.Pcre && c1 = 'E' + then + set {state with disabled_metacharacters := false} + pure (⟨2, by simp⟩ , none) + else + let (⟨n, _⟩ , p) ← parse_escape pattern (i + 1) true + pure (NatPos.succ n, p) | _ => let lit := ⟨⟨pattern, ⟨i⟩, ⟨i + 1⟩⟩, LiteralKind.Verbatim, c⟩ - Except.ok (⟨1, by simp⟩ , Primitive.Literal lit) + pure (⟨1, by simp⟩ , Primitive.Literal lit) /-- Parse a single primitive item in a character class set. -/ private def parse_set_class_range (pattern : String) (i : Nat) - : Except String (NatPos × ClassSetItem) := do + : ParserM (NatPos × ClassSetItem) := do let (⟨n1, h⟩, prim1) ← parse_set_class_item pattern i - let c := pattern.getAtCodepoint (i + n1) - if c != '-' || (pattern.getAtCodepoint (i + n1 + 1)) = ']' - then - Except.ok (⟨n1, h⟩, ←prim1.into_class_set_item) - else - let (⟨n2, _⟩, prim2) ← parse_set_class_item pattern (i + n1 + 1) - let lit1 ←prim1.into_class_literal - let lit2 ←prim2.into_class_literal - if h : lit1.c.val <= lit2.c.val + match prim1 with + | some prim1 => + let c := pattern.getAtCodepoint (i + n1) + let state ← get + if c != '-' || (pattern.getAtCodepoint (i + n1 + 1)) = ']' || state.disabled_metacharacters then - let range : ClassSetRange := - ⟨⟨pattern, ⟨i⟩, ⟨i + n1 + n2 + 1⟩⟩, lit1, lit2, h⟩ - Except.ok (⟨1 + n1 + n2, by simp_arith[Nat.zero_lt_one_add _]⟩, ClassSetItem.Range range) - else Except.error (toError pattern .ClassRangeInvalid) + pure (⟨n1, h⟩, ←prim1.into_class_set_item) + else + let (⟨n2, _⟩, prim2) ← parse_set_class_item pattern (i + n1 + 1) + match prim2 with + | some prim2 => + let lit1 ←prim1.into_class_literal + let lit2 ←prim2.into_class_literal + if h : lit1.c.val <= lit2.c.val + then + let range : ClassSetRange := + ⟨⟨pattern, ⟨i⟩, ⟨i + n1 + n2 + 1⟩⟩, lit1, lit2, h⟩ + pure (⟨1 + n1 + n2, by simp_arith[Nat.zero_lt_one_add _]⟩, ClassSetItem.Range range) + else Except.error (toError pattern .ClassRangeInvalid) + | none => Except.error (toError pattern .ClassRangeInvalid) + | none => pure (⟨n1, h⟩, ClassSetItem.Empty "".toSubstring) /-- Parses the opening of a character class set. -/ private def parse_set_class_open (pattern : String) (i : Nat) @@ -440,6 +596,8 @@ def push_class_op (next_kind: ClassSetBinaryOpKind) (next_union: ClassSetUnion) private def parse_set_class_loop (pattern : String) (i : Nat) (union : ClassSetUnion) : ParserM (NChars × ClassBracketed) := do + let flavor ← read + let state ← get let handle_other_char (span : Substring) (items : Array ClassSetItem) (h₀ : ¬i ≥ String.length pattern) : ParserM (NChars × ClassBracketed) := do let (⟨n, h⟩, range) ← parse_set_class_range pattern i @@ -455,6 +613,7 @@ private def parse_set_class_loop (pattern : String) (i : Nat) (union : ClassSetU let c := pattern.getAtCodepoint i match c with | '[' => + if state.disabled_metacharacters then handle_other_char span items h₀ else let maybe_parsed := if (← get).stack_class.size > 0 then @@ -468,11 +627,17 @@ private def parse_set_class_loop (pattern : String) (i : Nat) (union : ClassSetU let (n, union) ← match maybe_parsed with | some (n, union) => pure (n, union) - | none => push_class_open pattern i union + | none => + if flavor == Syntax.Flavor.Pcre && (← get).stack_class.size > 0 then + let (⟨n, _⟩, range) ← parse_set_class_range pattern i + let union : ClassSetUnion := ⟨span, items.push range⟩ + pure (n-1, union) + else push_class_open pattern i union have : pattern.length - (i + n + 1) < pattern.length - i := Nat.sum_succ_lt_of_not_gt pattern.length i n h₀ parse_set_class_loop pattern (i + n + 1) union | ']' => + if state.disabled_metacharacters then handle_other_char span items h₀ else match ← pop_class union with | Sum.inl nested_union => have : pattern.length - (i + 1) < pattern.length - i := @@ -518,20 +683,27 @@ private def parse_set_class (pattern : String) (i : Nat) else throw s!"parse_set_class: internal error excpeted i {i} < i' {i'}" /-- Parse a primitive AST. e.g., A literal, non-set character class or assertion.-/ -private def parse_primitive (pattern : String) (i : Nat) : Except String (NatPos × Primitive) := do +private def parse_primitive (pattern : String) (i : Nat) : ParserM (NatPos × Primitive) := do + let flavor ← read let c := pattern.getAtCodepoint i match c with | '\\' => - let (⟨n, _⟩, p) ← parse_escape pattern (i + 1) - Except.ok (⟨1 + n, Nat.zero_lt_one_add _⟩, p) - | '.' => Except.ok (⟨1, by simp⟩, Primitive.Dot (String.toSpan pattern i (i + 1))) - | '^' => Except.ok (⟨1, by simp⟩, + match ← maybe_parse_backref pattern (i + 1) with + | some (n, br) => pure (NatPos.succ n, Primitive.BackRef br) + | none => + let (⟨n, _⟩, p) ← parse_escape pattern (i + 1) + pure (⟨1 + n, Nat.zero_lt_one_add _⟩, p) + | '.' => pure (⟨1, by simp⟩, Primitive.Dot (String.toSpan pattern i (i + 1))) + | '^' => pure (⟨1, by simp⟩, Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.StartLine⟩) - | '$' => Except.ok (⟨1, by simp⟩, - Primitive.Assertion ⟨String.toSpan pattern i (i + 1), AssertionKind.EndLine⟩) + | '$' => pure (⟨1, by simp⟩, + Primitive.Assertion ⟨String.toSpan pattern i (i + 1), + if flavor == Flavor.Pcre + then AssertionKind.EndLineWithOptionalLF + else AssertionKind.EndLine⟩) | _ => let lit := ⟨⟨pattern, ⟨i⟩, ⟨i + 1⟩⟩, LiteralKind.Verbatim, c⟩ - Except.ok (⟨1, by simp⟩, Primitive.Literal lit) + pure (⟨1, by simp⟩, Primitive.Literal lit) /-- Parses an uncounted repetition operation. -/ private def parse_uncounted_repetition (pattern : String) (i : Nat) (kind: RepetitionKind) @@ -595,6 +767,7 @@ private def parse_flags (pattern : String) (i : Nat) /-- Parse a group (which contains a sub-expression) or a set of flags. -/ private def parse_group (pattern : String) (i : Nat) : ParserM (NChars × (Sum SetFlags Group)) := do + let flavor ← read let parser ← get let c1 := pattern.getAtCodepoint i let c2 := pattern.getAtCodepoint (i + 1) @@ -607,13 +780,50 @@ private def parse_group (pattern : String) (i : Nat) let g := Group.mk (String.toSpan pattern i (i + n + 1)) (.CaptureIndex parser.capture_index) Ast.Empty set parser pure (n, Sum.inr g) + else if c1 = '?' && c2 = '#' then + let chars := (pattern.data.drop (i+1)).takeWhile (· != ')') + let n := chars.length + 2 + let s : String := ⟨chars⟩ + let sf : SetFlags := ⟨String.toSpan pattern i (i + 1), ⟨s.toSubstring, #[]⟩ ⟩ + pure (n, Sum.inl sf) + else if c1 = '?' && c2 = '=' then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround .PositiveLookahead) Ast.Empty + pure (2, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "pla:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround .PositiveLookahead) Ast.Empty + pure (5, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "nla:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround .NegativeLookahead) Ast.Empty + pure (5, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "positive_lookahead:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround .PositiveLookahead) Ast.Empty + pure (20, Sum.inr g) + else if c1 = '?' && c2 = '!' then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround .NegativeLookahead) Ast.Empty + pure (2, Sum.inr g) + else if c1 = '?' && c2 = '<' && c3 = '=' then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround (.PositiveLookbehind 0)) Ast.Empty + pure (3, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "plb:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround (.PositiveLookbehind 0)) Ast.Empty + pure (5, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "positive_lookbehind:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround (.PositiveLookbehind 0)) Ast.Empty + pure (21, Sum.inr g) + else if c1 = '*' && String.startsAtCodepoint pattern "nlb:" (i+1) then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround (.NegativeLookbehind 0)) Ast.Empty + pure (5, Sum.inr g) + else if c1 = '?' && c2 = '<' && c3 = '!' then + let g := Group.mk (String.toSpan pattern i (i + 1)) (.Lookaround (.NegativeLookbehind 0)) Ast.Empty + pure (3, Sum.inr g) else if c1 = '?' then let (n, flags) ← parse_flags pattern (i + 1) let c1 := pattern.getAtCodepoint (i + 1 + n) if c1 = ')' then - if flags.items.size = 0 then Except.error (toError pattern .RepetitionMissing) + if flavor != Syntax.Flavor.Pcre && flags.items.size = 0 + then Except.error (toError pattern .RepetitionMissing) else let sf : SetFlags := ⟨String.toSpan pattern i (i + 1), flags⟩ pure (n + 2, Sum.inl sf) @@ -632,12 +842,68 @@ private def push_group (pattern : String) (i : Nat) (concat : Concat) let (n, group) ← parse_group pattern i match group with | .inl flags => - pure (n, Concat.mk (String.toSpan pattern i (i + 1)) (concat.asts.push (Ast.Flags flags))) + match flags with + | ⟨_, ⟨_, #[]⟩⟩ => pure (n, concat) + | _ => pure (n, Concat.mk (String.toSpan pattern i (i + 1)) (concat.asts.push (Ast.Flags flags))) | .inr group => let parser ← get set {parser with stack_group := parser.stack_group.push (GroupState.Group concat group)} pure (n, Concat.mk (String.toSpan pattern i (i + 1)) #[]) +private def get_fixed_width (pattern : String) (ast : Ast) : ParserM Nat := do + match ast with + | .Literal _ => pure 1 + | .Dot _ => pure 1 + | .ClassBracketed _ => pure 1 + | .ClassUnicode _ => pure 1 + | .ClassPerl _ => pure 1 + | .Assertion _ => pure 0 + | .Flags _ => pure 0 + | .Concat concat => + match concat with + | ⟨_, asts⟩ => + let width ← asts.attach.foldlM (init := 0) (fun s ast => do + have : sizeOf ast.val < sizeOf asts := Array.sizeOf_lt_of_mem ast.property + let width ← get_fixed_width pattern ast.val + pure (s + width)) + pure width + | .Alternation alt => + match alt with + | ⟨_, asts⟩ => + let widths ← asts.attach.mapM (fun ast => do + have : sizeOf ast.val < sizeOf asts := Array.sizeOf_lt_of_mem ast.property + let width ← get_fixed_width pattern ast.val + pure width) + if h : 0 < widths.size + then + let width := widths.get ⟨0, h⟩ + if Array.all widths (fun w => w = width) + then pure width + else throw (toError pattern .FixedWidtExcpected) + else throw (toError pattern .FixedWidtExcpected) + | .Repetition rep => + match rep with + | AstItems.Repetition.mk _ (RepetitionOp.mk _ (.Range (.Exactly n))) _ _ => pure n + | _ => throw (toError pattern .FixedWidtExcpected) + | .Group ⟨_, GroupKind.CaptureIndex _, ast⟩ => + let width ← get_fixed_width pattern ast + pure width + | .Group ⟨_, GroupKind.Lookaround _, _⟩ => + pure 0 + | _ => throw (toError pattern .FixedWidtExcpected) +termination_by sizeOf ast + +/-- set fixed width for look behind -/ +private def set_width (pattern : String) (g : Group) : ParserM Group := do + match g with + | ⟨span, .Lookaround (.PositiveLookbehind _), ast⟩ => + let width ← get_fixed_width pattern ast + pure (Group.mk span (.Lookaround (.PositiveLookbehind width)) ast) + | ⟨span, .Lookaround (.NegativeLookbehind _), ast⟩ => + let width ← get_fixed_width pattern ast + pure (Group.mk span (.Lookaround (.NegativeLookbehind width)) ast) + | _ => pure g + /-- Pop a group AST from the parser's internal stack and set the group's AST to the concatenation.-/ private def pop_group (pattern : String) (i : Nat) (group_concat : Concat) : ParserM Concat := do @@ -645,6 +911,7 @@ private def pop_group (pattern : String) (i : Nat) (group_concat : Concat) match Array.pop? parser.stack_group with | some (GroupState.Group prior_concat ⟨⟨s, start, _⟩ , kind, _⟩ , stack_group) => let group := Group.mk ⟨s, start, ⟨i⟩ ⟩ kind group_concat.into_ast + let group ← set_width pattern group let prior_concat := Concat.mk prior_concat.span (prior_concat.asts.push (Ast.Group group)) set {parser with stack_group := stack_group } pure prior_concat @@ -675,64 +942,113 @@ private def pop_group_end (pattern : String) (concat : Concat) (parser : Parser) | none => Except.ok concat.into_ast +private def add_char_to_concat (pattern : String) (i : Nat) (c : Char) (concat : Concat) : Concat := + let lit : Literal := ⟨⟨pattern, ⟨i⟩, ⟨i + 1⟩⟩, LiteralKind.Verbatim, c⟩ + let p : Primitive := Primitive.Literal lit + let asts := concat.asts.push p.into_ast + (Concat.mk (concat.span) asts) + /-- Parse the regular expression and return an abstract syntax tree. -/ -def parse (pattern : String) : Except String Ast := do +def parse (pattern : String) (flavor : Syntax.Flavor) : Except String Ast := do let concat : Concat := Concat.mk (String.toSpan pattern 0 pattern.length) #[] - let (concat, parser) ← loop pattern 0 concat default - pop_group_end pattern concat parser + let (concat, parser) ← loop pattern 0 concat flavor default + if parser.capture_index < parser.max_backreference + then Except.error (toError pattern .BackRefenceInvalid) + else pop_group_end pattern concat parser where /-- loop over chars of `pattern` to parse the regular expression -/ - loop (pattern : String) (i : Nat) (concat : Concat) : ParserM Concat := do - if h₀ : i >= pattern.length - then pure concat - else - let c := pattern.getAtCodepoint i - match c with - | '(' => - let (n, concat) ← push_group pattern (i + 1) concat - have : pattern.length - (i + n + 1) < pattern.length - i := by - simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] - loop pattern (i+n+1) concat - | ')' => - let concat ← pop_group pattern (i + 1) concat - have : pattern.length - (i + 1) < pattern.length - i := by - simp [Nat.succ_lt_of_not_gt _ _ h₀] - loop pattern (i+1) concat - | '|' => - let concat ← push_alternate pattern i concat - have : pattern.length - (i + 1) < pattern.length - i := by - simp [Nat.succ_lt_of_not_gt _ _ h₀] - loop pattern (i+1) concat - | '[' => - let (⟨n, h₁⟩, cls) ← parse_set_class pattern i - let asts := concat.asts.push (Ast.ClassBracketed cls) - have : pattern.length - (i + n) < pattern.length - i := by - simp [Nat.sum_lt_of_not_gt _ _ _ h₀ h₁] - loop pattern (i+n) (Concat.mk (concat.span) asts) - | '?' => - let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.ZeroOrOne concat - have : pattern.length - (i + n + 1) < pattern.length - i := by - simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] - loop pattern (i+n+1) p - | '*' => - let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.ZeroOrMore concat - have : pattern.length - (i + n + 1) < pattern.length - i := by - simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] - loop pattern (i+n+1) p - | '+' => - let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.OneOrMore concat - have : pattern.length - (i + n + 1) < pattern.length - i := by - simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] - loop pattern (i+n+1) p - | '{' => - let (n, concat) ← parse_counted_repetition pattern (i + 1) concat - have : pattern.length - (i + n + 1) < pattern.length - i := by - simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] - loop pattern (i+n+1) concat - | _ => - let (⟨n, h₁⟩, p) ← parse_primitive pattern i - let asts := concat.asts.push p.into_ast - have : pattern.length - (i + n) < pattern.length - i := by - simp [Nat.sum_lt_of_not_gt _ _ _ h₀ h₁] - loop pattern (i+n) (Concat.mk (concat.span) asts) - termination_by pattern.length - i + loop (pattern : String) (i' : Nat) (concat : Concat) : ParserM Concat := do + let flavor ← read + let state ← get + let i := consume_space concat pattern i' + have : i' ≤ i := consume_space_ge concat pattern i' + if h₀ : i >= pattern.length + then pure concat + else + let c := pattern.getAtCodepoint i + match c with + | '(' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let (n, concat) ← push_group pattern (i + 1) concat + have : pattern.length - (i + n + 1) < pattern.length - i := by + simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] + loop pattern (i+n+1) concat + | ')' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let concat ← pop_group pattern (i + 1) concat + have : pattern.length - (i + 1) < pattern.length - i := by + simp [Nat.succ_lt_of_not_gt _ _ h₀] + loop pattern (i+1) concat + | '|' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let concat ← push_alternate pattern i concat + have : pattern.length - (i + 1) < pattern.length - i := by + simp [Nat.succ_lt_of_not_gt _ _ h₀] + loop pattern (i+1) concat + | '[' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let (⟨n, h₁⟩, cls) ← parse_set_class pattern i + let asts := concat.asts.push (Ast.ClassBracketed cls) + have : pattern.length - (i + n) < pattern.length - i := by + simp [Nat.sum_lt_of_not_gt _ _ _ h₀ h₁] + loop pattern (i+n) (Concat.mk (concat.span) asts) + | '?' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.ZeroOrOne concat + have : pattern.length - (i + n + 1) < pattern.length - i := by + simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] + loop pattern (i+n+1) p + | '*' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.ZeroOrMore concat + have : pattern.length - (i + n + 1) < pattern.length - i := by + simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] + loop pattern (i+n+1) p + | '+' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + let (n, p) ← parse_uncounted_repetition pattern i RepetitionKind.OneOrMore concat + have : pattern.length - (i + n + 1) < pattern.length - i := by + simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] + loop pattern (i+n+1) p + | '{' => + if state.disabled_metacharacters + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + match parse_counted_repetition pattern (i + 1) concat with + | Except.ok (n, concat) => + have : pattern.length - (i + n + 1) < pattern.length - i := by + simp [Nat.sum_succ_lt_of_not_gt _ _ _ h₀] + loop pattern (i+n+1) concat + | Except.error e => + if flavor == Flavor.Pcre + then loop pattern (i+1) (add_char_to_concat pattern i c concat) else + throw e + | _ => + let c1 := pattern.getAtCodepoint (i + 1) + if flavor == Flavor.Pcre && c = '\\' && c1 = 'Q' + then + set {state with disabled_metacharacters := true} + loop pattern (i+2) concat + else if flavor == Flavor.Pcre && c = '\\' && c1 = 'E' + then + if !state.disabled_metacharacters + then throw (toError pattern .EndQuoteWithoutOpenQuote) + else + set {state with disabled_metacharacters := false} + loop pattern (i+2) concat + else if c = '\\' && state.disabled_metacharacters + then + loop pattern (i+1) (add_char_to_concat pattern i c concat) + else + let (⟨n, h₁⟩, p) ← parse_primitive pattern i + let asts := concat.asts.push p.into_ast + have : pattern.length - (i + n) < pattern.length - i := by + simp [Nat.sum_lt_of_not_gt _ _ _ h₀ h₁] + loop pattern (i+n) (Concat.mk (concat.span) asts) + termination_by pattern.length - i' diff --git a/Regex/Syntax/Ast/Visitor.lean b/Regex/Syntax/Ast/Visitor.lean index 9fedec5..75f44f8 100644 --- a/Regex/Syntax/Ast/Visitor.lean +++ b/Regex/Syntax/Ast/Visitor.lean @@ -101,7 +101,7 @@ private def visit_class [Inhabited α] (ast: ClassBracketed) def visit_loop {α σ: Type} [Inhabited α] (β : Visitor α σ) (ast : Ast) : M σ String PUnit := do β.visit_pre ast let res ← match h : ast with - | .Empty | .Flags _ | .Literal _ | .Dot _ | .Assertion _ | .ClassUnicode _ | .ClassPerl _ => + | .Empty | .Flags _ | .Literal _ | .BackRef _ | .Dot _ | .Assertion _ | .ClassUnicode _ | .ClassPerl _ => pure default | .ClassBracketed cls => visit_class cls β diff --git a/Regex/Syntax/Hir.lean b/Regex/Syntax/Hir.lean index 20e0643..9d22450 100644 --- a/Regex/Syntax/Hir.lean +++ b/Regex/Syntax/Hir.lean @@ -1,4 +1,4 @@ -import Std.Data.Array.Basic +import Batteries.Data.Array.Basic import Regex.Utils import Regex.Interval import Regex.Unicode @@ -86,6 +86,8 @@ inductive Look where | Start : Look /-- Match the end of text. -/ | End : Look + /-- Match the end of text (before optional newline). -/ + | EndWithOptionalLF : Look /-- Match the beginning of a line or the beginning of text. -/ | StartLF : Look /-- Match the end of a line or the end of text. -/ @@ -113,6 +115,7 @@ namespace Look def toString : Look -> String | .Start => s!"Start" | .End => s!"End" + | .EndWithOptionalLF => s!"EndWithOptionalLF" | .StartLF => s!"StartLF" | .EndLF => s!"EndLF" | .StartCRLF => s!"StartCRLF" @@ -153,6 +156,13 @@ instance : ToString Flags where mutual +/-- The high-level intermediate representation for a look-around assertion. -/ +inductive Lookaround where + | PositiveLookahead : Hir -> Lookaround + | NegativeLookahead : Hir -> Lookaround + | PositiveLookbehind : Nat -> Hir -> Lookaround + | NegativeLookbehind : Nat -> Hir -> Lookaround + /-- A concatenation of regular expressions. -/ inductive Repetition where | mk (min: Nat) (max: Option Nat) (greedy : Bool) (sub: Hir) : Repetition @@ -167,10 +177,14 @@ inductive HirKind where | Empty : HirKind /-- A literal string that matches exactly these bytes. -/ | Literal : Char -> HirKind + /-- A backrefence to a capturung group. -/ + | BackRef : Bool -> Nat -> HirKind /-- A single character class that matches any of the characters in the class. -/ | Class : Class -> HirKind /-- A look-around assertion. A look-around match always has zero length. -/ | Look : Look -> HirKind + /-- A complex look-around assertion. -/ + | Lookaround : Lookaround -> HirKind /-- A repetition operation applied to a sub-expression. -/ | Repetition : Repetition -> HirKind /-- A capturing group, which contains a sub-expression. -/ @@ -195,8 +209,15 @@ def fold [Inhabited α] (hir : Hir) (f : α -> Hir -> α) (init : α): α := match kind with | .Empty => f init hir | .Literal _ => f init hir + | .BackRef _ _ => f init hir | .Class _ => f init hir | .Look _ => f init hir + | .Lookaround look => + match look with + | .PositiveLookahead sub => fold sub f init + | .NegativeLookahead sub => fold sub f init + | .PositiveLookbehind _ sub => fold sub f init + | .NegativeLookbehind _ sub => fold sub f init | .Repetition ⟨_, _, _, sub⟩ => fold sub f init | .Capture _ => f init hir | .Concat hirs => hirs.attach |> Array.foldl (init := init) @@ -240,8 +261,27 @@ def toString (hir : Hir) (col : Nat): String := match hk : hir.kind with | .Empty => s!"Empty" | .Literal c => s!"Literal '{UInt32.intAsString c.val}'" + | .BackRef f n => s!"BackRef {if f then "case_insensitive" else ""}'{n}'" | .Class cls => s!"Class {cls}" | .Look look => s!"Look {look}" + | .Lookaround lk => + match hr: lk with + | .PositiveLookahead sub => + have : sizeOf lk < sizeOf hir.kind := by simp [hk, hr] + have : sizeOf sub < sizeOf lk := by simp [hr] + s!"PositiveLookahead {toString sub col}" + | .NegativeLookahead sub => + have : sizeOf lk < sizeOf hir.kind := by simp [hk, hr] + have : sizeOf sub < sizeOf lk := by simp [hr] + s!"NegativeLookahead {toString sub col}" + | .PositiveLookbehind i sub => + have : sizeOf lk < sizeOf hir.kind := by simp [hk, hr] + have : sizeOf sub < sizeOf lk := by simp [hr]; omega + s!"PositiveLookbehind Length {i} {toString sub col}" + | .NegativeLookbehind i sub => + have : sizeOf lk < sizeOf hir.kind := by simp [hk, hr] + have : sizeOf sub < sizeOf lk := by simp [hr]; omega + s!"NegativeLookbehind Length {i} {toString sub col}" | .Repetition rep => match hr : rep with | .mk min max greedy sub => @@ -315,6 +355,7 @@ def dot (dot: Dot) : Hir := inductive HirFrame where | Expr : Hir -> HirFrame | Literal : Char -> HirFrame + | BackRef : Bool -> Nat -> HirFrame | ClassUnicode : ClassUnicode -> HirFrame | Repetition : HirFrame | Group : (old_flags: Syntax.Flags) -> HirFrame @@ -326,6 +367,7 @@ namespace HirFrame def toString : HirFrame -> String | .Expr hir => s!"Expr '{hir}'" | .Literal c => s!"Literal {c}" + | .BackRef f n => s!"BackRef {if f then "case_insensitive" else ""} {n}" | .ClassUnicode cls => s!"ClassUnicode cls set size {cls.set.intervals.size}" | .Repetition => "Repetition" | .Group flags => s!"Group {flags}" @@ -336,6 +378,7 @@ def unwrap_expr (frame : HirFrame) : Except String Hir := match frame with | .Expr expr => Except.ok expr | .Literal c => Except.ok ⟨HirKind.Literal c, default⟩ + | .BackRef f n => Except.ok ⟨HirKind.BackRef f n, default⟩ | _ => Except.error "unwrap_expr, Literal or Expr expected" /-- Assert that the current stack frame is a Unicode class expression and return it.-/ diff --git a/Regex/Syntax/Translate.lean b/Regex/Syntax/Translate.lean index 4963bf2..003b16c 100644 --- a/Regex/Syntax/Translate.lean +++ b/Regex/Syntax/Translate.lean @@ -194,10 +194,15 @@ private def hir_assertion (ast : AstItems.Assertion) (flags : Syntax.Flags) : Hi | .EndLine => if multi_line then if crlf then HirKind.Look (.EndCRLF) else HirKind.Look (.EndLF) else HirKind.Look (.End) + | .EndLineWithOptionalLF => + if multi_line then if crlf then HirKind.Look (.EndCRLF) else HirKind.Look (.EndLF) + else HirKind.Look (Look.EndWithOptionalLF) | .StartText => HirKind.Look (Look.Start) | .EndText => HirKind.Look (Look.End) + | .EndTextWithOptionalLF => + HirKind.Look (Look.EndWithOptionalLF) | .WordBoundary => HirKind.Look (Look.WordUnicode) | .NotWordBoundary => @@ -218,12 +223,27 @@ private def hir_capture (g : AstItems.Group) (expr: Hir) : Hir := match g.kind with | .CaptureIndex captureIndex => (some captureIndex, none) | .NonCapturing _ => (none, none) + | .Lookaround _ => (none, none) match index with | some index => let cap : Syntax.Capture := Syntax.Capture.mk index name expr Hir.mk (HirKind.Capture cap) default - | none => expr + | none => + match g.kind with + | .Lookaround .PositiveLookahead => + let look : Syntax.Lookaround := Syntax.Lookaround.PositiveLookahead expr + Hir.mk (HirKind.Lookaround look) default + | .Lookaround .NegativeLookahead => + let look : Syntax.Lookaround := Syntax.Lookaround.NegativeLookahead expr + Hir.mk (HirKind.Lookaround look) default + | .Lookaround (.PositiveLookbehind i) => + let look : Syntax.Lookaround := Syntax.Lookaround.PositiveLookbehind i expr + Hir.mk (HirKind.Lookaround look) default + | .Lookaround (.NegativeLookbehind i) => + let look : Syntax.Lookaround := Syntax.Lookaround.NegativeLookbehind i expr + Hir.mk (HirKind.Lookaround look) default + | _ => expr def pop_concat_expr (stack : Array HirFrame) : Except String (Array HirFrame × Option Hir) := match Array.pop? stack with @@ -232,6 +252,7 @@ def pop_concat_expr (stack : Array HirFrame) : Except String (Array HirFrame × | .Concat => Except.ok (stack, none) | .Expr expr => Except.ok (stack, (some expr)) | .Literal c => Except.ok (stack, (some (Hir.mk (Syntax.HirKind.Literal c) default))) + | .BackRef f n => Except.ok (stack, (some (Hir.mk (Syntax.HirKind.BackRef f n) default))) | .ClassUnicode _ => Except.error "pop_concat_expr, unexpected frame" | .Repetition => Except.error "pop_concat_expr, unexpected frame .ClassUnicode" | .Group _ => Except.error "pop_concat_expr, unexpected frame .Group" @@ -262,6 +283,7 @@ def pop_alt_expr (stack : Array HirFrame) : Except String (Array HirFrame × Opt | .Alternation => Except.ok (stack, none) | .Expr expr => Except.ok (stack, (some expr)) | .Literal c => Except.ok (stack, (some (Hir.mk (Syntax.HirKind.Literal c) default))) + | .BackRef f n => Except.ok (stack, (some (Hir.mk (Syntax.HirKind.BackRef f n) default))) | __ => Except.error "pop_alt_expr, unexpected frame" | none => Except.ok (stack, none) @@ -331,6 +353,8 @@ def visit_post (ast: Ast) : StateT Translator (Except String) PUnit := do set {t with stack := t.stack.push (HirFrame.Expr expr)} else set {t with stack := push_char c t.stack} + | .BackRef ⟨_, n⟩ => + set {t with stack := t.stack.push (HirFrame.BackRef t.flags.is_case_insensitive n)} | .Dot _ => let expr := (hir_dot t.flags) set {t with stack := t.stack.push (HirFrame.Expr expr)} diff --git a/Regex/Utils.lean b/Regex/Utils.lean index d4f14ce..2418e2a 100644 --- a/Regex/Utils.lean +++ b/Regex/Utils.lean @@ -1,4 +1,4 @@ -import Std.Data.List.Lemmas +import Batteries.Data.List.Lemmas /-! ## Utils @@ -10,6 +10,12 @@ namespace Char def multiple (c : Char) ( n : Nat) (acc : String ): String := if n = 0 then acc else multiple c ( n - 1) (c.toString ++ acc) +def isHexDigit (c : Char) : Bool := + if '0' ≤ c && c ≤ '9' then true + else if 'a' ≤ c && c ≤ 'f' then true + else if 'A' ≤ c && c ≤ 'F' then true + else false + def decodeHexDigit (c : Char) : Option (UInt32) := if '0' ≤ c && c ≤ '9' then some (c.val - '0'.val) else if 'a' ≤ c && c ≤ 'f' then some (10 + c.val - 'a'.val) @@ -22,8 +28,19 @@ def decodeHexDigits (chars : List Char) : Except String UInt32 := let (_, val) := l |> List.foldr (init := (1, 0)) (fun v (n, acc) => (n*16, acc + n*v)) Except.ok val - --| [some u1, some u2, some u3, some u4] => Except.ok (4096*u1 + 256*u2 + 16*u3 + u4) - else Except.error s!"hexCharsToVal, invalid arg {chars}" + else Except.error s!"decodeHexDigits, invalid arg {chars}" + +def decodeOctDigit (c : Char) : Option (UInt32) := + if '0' ≤ c && c ≤ '7' then some (c.val - '0'.val) + else none + +def decodeOctDigits (chars : List Char) : Except String UInt32 := + let l := chars |> List.filterMap (decodeOctDigit ·) + if l.length > 0 then + let (_, val) := l |> List.foldr (init := (1, 0)) (fun v (n, acc) => + (n*8, acc + n*v)) + Except.ok val + else Except.error s!"decodeOctDigits, invalid arg {chars}" end Char @@ -63,6 +80,14 @@ namespace String def getAtCodepoint (s : String) (i : Nat) : Char := if h : i < s.length then s.data.get ⟨i, h⟩ else default +/-- starts string `m` at codepoint `i` in `s` -/ +def startsAtCodepoint (s m : String) (i : Nat) : Bool := + if i + m.length ≤ s.length + then + let s := (s.toSubstring).drop i + s.toString.startsWith m + else false + /-- compute the byte position of the codepoint position `p` in `s` -/ def toBytePosition (s : String) (p : Nat) : String.Pos := ⟨String.utf8ByteSize ⟨s.data |> List.take p⟩⟩ diff --git a/lake-manifest.json b/lake-manifest.json index 2d21f3d..b0e6d2a 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -4,17 +4,17 @@ [{"url": "https://github.com/fgdorais/lean4-unicode-basic.git", "type": "git", "subDir": null, - "rev": "8b53cc65534bc2c6888c3d4c53a3439648213f74", + "rev": "87791b59c53be80a9a000eb2bcbf61f60a27b334", "name": "UnicodeBasic", "manifestFile": "lake-manifest.json", "inputRev": "main", "inherited": false, "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover/std4", + {"url": "https://github.com/leanprover-community/batteries", "type": "git", "subDir": null, - "rev": "3025cb124492b423070f20cf0a70636f757d117f", - "name": "std", + "rev": "551ff2d7dffd7af914cdbd01abbd449fe3e3d428", + "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", "inherited": true, @@ -22,7 +22,7 @@ {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, - "rev": "64365c656d5e1bffa127d2a1795f471529ee0178", + "rev": "53156671405fbbd5402ed17a79bd129b961bd8d6", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -31,19 +31,19 @@ {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, - "rev": "0a21a48c286c4a4703c0be6ad2045f601f31b1d0", + "rev": "53ba96ad7666d4a2515292974631629b5ea5dfee", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", "inherited": true, - "configFile": "lakefile.lean"}, + "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, - "rev": "fe1eff53bd0838c657aa6126fe4dd75ad9939d9a", + "rev": "e6b6247c61280c77ade6bbf0bc3c66a44fe2e0c5", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.35", + "inputRev": "v0.0.36", "inherited": true, "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover/lean4-cli", @@ -58,19 +58,19 @@ {"url": "https://github.com/leanprover-community/import-graph.git", "type": "git", "subDir": null, - "rev": "188eb34fcf1125e89d651ad462d02598219718ca", + "rev": "77e081815b30b0d30707e1c5b0c6a6761f7a2404", "name": "importGraph", "manifestFile": "lake-manifest.json", "inputRev": "main", "inherited": true, - "configFile": "lakefile.lean"}, + "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/mathlib4", "type": "git", "subDir": null, - "rev": "db651742f2c631e5b8525e9aabcf3d61ed094a4a", + "rev": "b5eba595428809e96f3ed113bc7ba776c5f801ac", "name": "mathlib", "manifestFile": "lake-manifest.json", - "inputRev": "v4.8.0-rc1", + "inputRev": "v4.8.0", "inherited": false, "configFile": "lakefile.lean"}], "name": "Regex", diff --git a/lakefile.lean b/lakefile.lean index d1b38bd..c8169b1 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -3,12 +3,12 @@ open Lake DSL meta if get_config? env = some "dev" then require «doc-gen4» from git "https://github.com/leanprover/doc-gen4" - @ "main" + @ "c7f4ac84b973b6efd8f24ba2b006cad1b32c9c53" require UnicodeBasic from git "https://github.com/fgdorais/lean4-unicode-basic.git" @ "main" -require mathlib from git "https://github.com/leanprover-community/mathlib4" @ "v4.8.0-rc1" +require mathlib from git "https://github.com/leanprover-community/mathlib4" @ "v4.8.0" package «Regex» { } @@ -32,7 +32,7 @@ lean_exe benchmark { lean_lib Test where srcDir := "test" - roots := #[`Test, `RegexTest, `TomlLoader] + roots := #[`Test, `RegexTest, `TomlLoader, `PcreLoader] @[test_runner] lean_exe test where diff --git a/lean-toolchain b/lean-toolchain index d8a6d7e..ef1f67e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.8.0-rc1 +leanprover/lean4:v4.8.0 diff --git a/scripts/nolints.json b/scripts/nolints.json index 5cca4dc..959e0fe 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -1,5 +1,8 @@ [["docBlame", "Char.decodeHexDigit"], ["docBlame", "Char.decodeHexDigits"], + ["docBlame", "Char.decodeOctDigit"], + ["docBlame", "Char.decodeOctDigits"], + ["docBlame", "Char.isHexDigit"], ["docBlame", "Compiler.CompilerM"], ["docBlame", "IntervalSet.intervals"], ["docBlame", "Intervals.singleton"], @@ -33,6 +36,7 @@ ["docBlame", "Unicode.rangesOfSentenceBreak"], ["docBlame", "Unicode.toRange"], ["docBlame", "BoundedBacktracker.CharPos.get?"], + ["docBlame", "BoundedBacktracker.CharPos.prevOf"], ["docBlame", "BoundedBacktracker.Stack.toStack"], ["docBlame", "BoundedBacktracker.backtrack.loop"], ["docBlame", "BoundedBacktracker.steps.loop"], @@ -55,6 +59,7 @@ ["docBlame", "Regex.Notation.toNumLit"], ["docBlame", "Syntax.AstItems.M"], ["docBlame", "Syntax.AstItems.ParserM"], + ["docBlame", "Syntax.AstItems.is_whitespace_enabled"], ["docBlame", "Syntax.AstItems.span"], ["docBlame", "Syntax.AstItems.spanToString"], ["docBlame", "Syntax.AstItems.toError"], @@ -130,6 +135,7 @@ ["docBlame", "Syntax.AstItems.Alternation.asts"], ["docBlame", "Syntax.AstItems.Alternation.into_ast"], ["docBlame", "Syntax.AstItems.AssertionKind.toString"], + ["docBlame", "Syntax.AstItems.BackRef.toString"], ["docBlame", "Syntax.AstItems.ClassAsciiKind.from_name"], ["docBlame", "Syntax.AstItems.ClassBracketed.negate"], ["docBlame", "Syntax.AstItems.ClassBracketed.span"], @@ -159,4 +165,4 @@ ["docBlame", "Syntax.AstItems.Repetition.op"], ["docBlame", "Syntax.AstItems.RepetitionKind.toString"], ["docBlame", "Syntax.AstItems.RepetitionOp.toString"], - ["docBlame", "Syntax.AstItems.RepetitionRange.toString"]] + ["docBlame", "Syntax.AstItems.RepetitionRange.toString"]] \ No newline at end of file diff --git a/test/PcreLoader.lean b/test/PcreLoader.lean new file mode 100644 index 0000000..0f00200 --- /dev/null +++ b/test/PcreLoader.lean @@ -0,0 +1,158 @@ +import Lean + +import RegexTest + +open Lean System + +namespace Loader.Pcre + +private def cZero : Char := ⟨0, by simp_arith⟩ + +private def octDigitsToChar! (chars : List Char) : Char := + match Char.decodeOctDigits chars with + | Except.ok n => if h : UInt32.isValidChar n then ⟨n, h⟩ else cZero + | Except.error _ => cZero + +/-- unescape strings from pcre json file generated from perltest.sh via JSON::PP. -/ +private def unescapeStr (s : String) (backslashIsEmptyString : Bool := false) : String := + ⟨loop s.data⟩ +where + toChar (a b : Char) : Char := + match Char.decodeHexDigit a, Char.decodeHexDigit b with + | some n, some m => + let val := 16*n+m + if h : UInt32.isValidChar val then ⟨val, h⟩ else ⟨0, by simp_arith⟩ + | _, _ => ⟨0, by simp_arith⟩ + loop (chars : List Char) : List Char := + match chars with + | [] => [] + | ['\\'] => if backslashIsEmptyString then [] else ['\\'] + | '\\' :: 'x' :: a :: b :: tail => + if b.isHexDigit + then (toChar a b) :: (loop tail) + else (toChar '0' a) :: (loop (b :: tail)) + | '\\' :: 'e' :: tail => ⟨27, by simp_arith⟩ :: (loop tail) + | '\\' :: 'n' :: tail => '\n' :: (loop tail) + | '\\' :: 'r' :: tail => '\r' :: (loop tail) + | '\\' :: '"' :: tail => '"' :: (loop tail) + | '\\' :: '$' :: tail => '$' :: (loop tail) + | '\\' :: '@' :: tail => '@' :: (loop tail) + | '\\' :: '\\' :: tail => '\\' :: (loop tail) + | '\\' :: 't' :: tail => '\t' :: (loop tail) + | '\\' :: c1 :: tail => + if c1.isDigit + then + match tail with + | c2 :: c3 :: tail => + if c2.isDigit && c3.isDigit then octDigitsToChar! [c1, c2, c3] :: (loop tail) + else if c2.isDigit then octDigitsToChar! [c1, c2] :: (loop (c3 :: tail)) + else octDigitsToChar! [c1] :: (loop (c2 :: c3 :: tail)) + | c2 :: [] => + if c2.isDigit then [octDigitsToChar! [c1, c2]] + else [octDigitsToChar! [c1], c2] + | [] => [octDigitsToChar! [c1]] + else '\\' :: c1 :: (loop tail) + | head :: tail => head :: (loop tail) + +example : unescapeStr r"\x20" = ⟨[' ']⟩ := by native_decide + +example : unescapeStr r"\x20\x20" = ⟨[' ', ' ']⟩ := by native_decide + +example : unescapeStr r"\0" = ⟨[cZero]⟩ := by native_decide + +example : unescapeStr r"\0\0" = ⟨[cZero, cZero]⟩ := by native_decide + +example : unescapeStr r"a\0" = ⟨['a', cZero]⟩ := by native_decide + +example : unescapeStr r"\0a" = ⟨[cZero, 'a']⟩ := by native_decide + +example : unescapeStr r"\12a" = ⟨['\n', 'a']⟩ := by native_decide + +example : unescapeStr r"\12" = ⟨['\n']⟩ := by native_decide + +example : unescapeStr r"\123" = ⟨['S']⟩ := by native_decide + +/-- A pcre match describes outputs of a pcre regex match generated from perltest.sh. -/ +private structure PcreMatch where + «match» : String + group1 : Option String + group2 : Option String + group3 : Option String + group4 : Option String + group5 : Option String + group6 : Option String + group7 : Option String + group8 : Option String + group9 : Option String + deriving Lean.FromJson + +/-- A pcre test describes the inputs and expected outputs of a pcre regex match + generated from perltest.sh. -/ +private structure PcreTest where + matchExpected : Nat + pattern : String + haystack : String + «match» : Option $ Array PcreMatch + noMatch : Option Bool + deriving Lean.FromJson + +private def toCaptures (p : PcreTest) : Array $ RegexTest.Captures := + match p.match with + | some arr => + let groups := + arr |> Array.map (fun m => + let _haystack := unescapeStr p.haystack true + let _match := unescapeStr m.«match» + + if _match.length = 0 then some ⟨0, 0, some _match⟩ else + match _haystack.splitOn _match with + | f :: _ => + some ⟨f.utf8ByteSize, f.utf8ByteSize + _match.utf8ByteSize, some _match⟩ + | _ => none) + #[⟨groups⟩] + | none => #[] + +private def setOption (c : Char) (t : RegexTest) : RegexTest := + match c with + | 'i' => { t with «case-insensitive» := some true } + | 's' => { t with single_line := some true } + | 'm' => { t with multi_line := some true } + | 'g' => { t with «global» := some true } + | 'x' => { t with extended := some true } + | _ => t + +private def toPattern (p : PcreTest) (t : RegexTest) : RegexTest := + let pattern := p.pattern.trim + match (pattern.data.head?, pattern.data.getLast?) with + | (some '/', some '/') => + { t with regex := Sum.inl ⟨(pattern.data.drop 1).dropLast⟩ } + | (some '/', some c1) => + let t := setOption c1 t + let data := (pattern.data.drop 1).dropLast + match data.getLast? with + | some '/' => { t with regex := Sum.inl ⟨data.dropLast⟩ } + | some c2 => + let t := setOption c2 t + { t with regex := Sum.inl ⟨data.dropLast.dropLast⟩ } + | none => t + | (_, _) => t + +private def toRegexTest (i : Nat) (p : PcreTest) : RegexTest := + toPattern p + { + name := s!"t{i}" + regex := Sum.inl "" + haystack := unescapeStr p.haystack true + «matches» := toCaptures p + «match-limit» := some 1 + unescape := some true + «only-full-match» := some true + } + +def toRegexTestArray (arr : Array PcreTest) : Array RegexTest := + Array.mapIdx arr (fun i p => toRegexTest i p) + +def load (path : FilePath) : IO (Array PcreTest) := do + let contents ← IO.FS.readFile path + let json ← IO.ofExcept <| Json.parse contents + IO.ofExcept <| fromJson? (α := Array PcreTest) json diff --git a/test/RegexTest.lean b/test/RegexTest.lean index 2f8844d..a3cb118 100644 --- a/test/RegexTest.lean +++ b/test/RegexTest.lean @@ -6,9 +6,12 @@ namespace RegexTest structure Span where start: Nat «end»: Nat + data: Option String instance : ToString Span where - toString s := s!"{s.start} {s.end}" + toString s := + let data := match s.data with | some data => " " ++ data.quote | none => "" + s!"{s.start} {s.end}{data}" /-- Captures represents a single group of captured matches from a regex search. -/ structure Captures where @@ -41,27 +44,33 @@ structure RegexTest where haystack : String «matches» : Array RegexTest.Captures /-- An optional field whose value is a table with `start` and `end` fields-/ - bounds : Option $ Array Nat + bounds : Option $ Array Nat := none /-- An optional field that specifies a limit on the number of matches. -/ - «match-limit» : Option Nat + «match-limit» : Option Nat := none /-- Whether to execute an anchored search or not. -/ - anchored : Option Bool + anchored : Option Bool := none /-- Whether to match the regex case insensitively. -/ - «case-insensitive» : Option Bool + «case-insensitive» : Option Bool := none /-- When enabled, the haystack is unescaped. -/ - unescape : Option Bool - compiles : Option Bool + unescape : Option Bool := none + compiles : Option Bool := none /-- When enabled, the regex pattern should be compiled with its corresponding Unicode mode enabled. -/ - unicode : Option Bool + unicode : Option Bool := none /-- When this is enabled, all regex match substrings should be entirely valid UTF-8. -/ - utf8 : Option Bool + utf8 : Option Bool := none /-- May be one of `all`, `leftmost-first` or `leftmost-longest`. -/ - «match-kind» : Option String + «match-kind» : Option String := none /-- May be one of `earliest`, `leftmost` or `overlapping`. -/ - «search-kind» : Option String + «search-kind» : Option String := none /-- This sets the line terminator used by the multi-line assertions -/ - «line-terminator» : Option String + «line-terminator» : Option String := none + /-- should check only full match of capture -/ + «only-full-match» : Option Bool := none + multi_line : Option Bool := none + single_line : Option Bool := none + «global» : Option Bool := none + extended : Option Bool := none namespace RegexTest @@ -83,25 +92,32 @@ end String def checkFlagIsFalse (f : Option Bool) : Bool := match f with | some v => !v | none => false +def checkFlagIsTrue (f : Option Bool) : Bool := + match f with | some v => v | none => false + private def escape (s : String) : String := - (s.replace "\n" "\\n").replace "\r" "\\r" + s.replace "\n" "\\n" |>.replace "\r" "\\r" |>.replace ⟨[⟨0, by simp_arith⟩]⟩ r"\x00" instance : ToString RegexTest where toString s := - let str := s!"{s.name} '{s.regex}' '{escape s.haystack}' {s.matches}" + let str := s!"{s.name} '{s.regex}' {s.haystack.quote} {s.matches}" let str := str ++ (if s.anchored.isSome then " anchored" else "") - let str := str ++ (if s.«case-insensitive».isSome then " case-insensitive" else "") + let str := str ++ (if checkFlagIsTrue s.«case-insensitive» then " case-insensitive" else "") let str := str ++ (if s.unescape.isSome then " unescape" else "") let str := str ++ (if s.unicode.isSome && !s.unicode.getD true then " !unicode" else "") let str := str ++ (if String.containsSubstr (Sum.val s.regex) "(?" then " flags" else "") let str := str ++ (if checkFlagIsFalse s.compiles then " !compiles" else "") + let str := str ++ (if checkFlagIsTrue s.single_line then " single_line" else "") + let str := str ++ (if checkFlagIsTrue s.multi_line then " multi_line" else "") + let str := str ++ (if checkFlagIsTrue s.global then " global" else "") + let str := str ++ (if checkFlagIsTrue s.extended then " extended" else "") str instance : ToString RegexTests where toString s := s!"{s.test}" def unescapeStr (s : String) : String := - ⟨loop s.data []⟩ + ⟨loop s.data⟩ where toChar (a b : Char) : Char := match Char.decodeHexDigit a, Char.decodeHexDigit b with @@ -109,29 +125,34 @@ where let val := 16*n+m if h : UInt32.isValidChar val then ⟨val, h⟩ else ⟨0, by simp_arith⟩ | _, _ => ⟨0, by simp_arith⟩ - loop (chars : List Char) (acc : List Char) : List Char := + loop (chars : List Char) : List Char := match chars with - | [] => acc - | '\\' :: 'x' :: a :: b :: tail => (toChar a b) :: (loop tail acc) - | '\\' :: 'n' :: tail => '\n' :: (loop tail acc) - | head :: tail => head :: (loop tail acc) - -def checkCompiles (t : RegexTest) : Bool := + | [] => [] + | '\\' :: 'x' :: a :: b :: tail => (toChar a b) :: (loop tail) + | '\\' :: 'n' :: tail => '\n' :: (loop tail) + | '\\' :: 'r' :: tail => '\r' :: (loop tail) + | '\\' :: '\\' :: tail => '\\' :: (loop tail) + | '\\' :: 't' :: tail => '\t' :: (loop tail) + | head :: tail => head :: (loop tail) + +def checkCompiles (flavor : Syntax.Flavor) (t : RegexTest) : Bool := let flags : Syntax.Flags := default let config : Compiler.Config := default - match Regex.build (Sum.val t.regex) flags config with + match Regex.build (Sum.val t.regex) flavor flags config with | Except.ok _ => true | Except.error _ => false -def captures (t : RegexTest) : Except String (Array Regex.Captures) := do +def captures (flavor : Syntax.Flavor) (t : RegexTest) : Except String (Array Regex.Captures) := do let flags : Syntax.Flags := default let config : Compiler.Config := default - let flags := {flags with case_insensitive := t.«case-insensitive»} + let flags := {flags with case_insensitive := t.«case-insensitive», + dot_matches_new_line := t.single_line, + multi_line := t.multi_line} let config := {config with unanchored_prefix := !t.anchored.getD false} let haystack := if t.unescape.getD false then unescapeStr t.haystack else t.haystack - let re ← Regex.build (Sum.val t.regex) flags config + let re ← Regex.build (Sum.val t.regex) flavor flags config Except.ok (Regex.all_captures haystack.toSubstring re) def checkMatches (arr : Array Regex.Captures) (t : RegexTest) : Bool := @@ -151,7 +172,7 @@ def checkMatches (arr : Array Regex.Captures) (t : RegexTest) : Bool := | some (some span), some v => span.start = v.startPos.byteIdx && span.end = v.stopPos.byteIdx | some none, none => true - | _, _ => false) + | _, _ => (Option.getD t.«only-full-match» false) && i.val > 0) else false) private def captureToString (r : Regex.Captures) : String := @@ -178,30 +199,70 @@ private def capturesToString (arr : Array Regex.Captures) : String := else s "[" ++ s ++ "]" +def extendedFlags := ["(?x", "(?^x"] +def atomicGroup := "(?>" +def conditionalExpression := "(?(" +def branchResetGroup := "(?|" + +def subroutines := ["(?0)", "(?1)", "(?2)", "(?3)", "(?4)", "(?5)", "(?6)", "(?7)", "(?+1)", "(?-2)"] + +/- todo -/ +def namedCaptureGroups := ["(? + List.any controlVerbs (fun v => let splits := s.splitOn v; splits.length > 1) + | Sum.inr _ => false + +def commentInRegex (regex : Sum String (Array String)) : Bool := + match regex with + | Sum.inl s => + let splits := s.splitOn "# " + splits.length > 1 + | Sum.inr _ => false + /-- ignore test, feature not implemented -/ def ignoreTest (t : RegexTest) : Bool := checkFlagIsFalse t.unicode || checkFlagIsFalse t.utf8 || t.bounds.isSome -- no api + || t.extended.isSome + || controlVerbInRegex t.regex + || commentInRegex t.regex || t.«line-terminator».isSome -- Config || t.«search-kind».any (· != "leftmost") -- only leftmost is valid for BoundedBacktracker || t.«match-kind».any (· = "all") -- Sets || match t.regex with | .inr _ => true | .inl _ => false -- Sets -def testItem (filename : String) (t : RegexTest) : IO (Nat × Nat × Nat) := do +/- todo -/ +def ignoredErrors := ["escape sequence unexpected in range"] + +/- todo -/ +def ignoredTests : List String := + ["t591", -- todo: slow + "t1474", "t1477", "t1478", "t1479", -- end quote without start quote + "t1488", "t1489" -- empty quote + ] + +def testItem (flavor : Syntax.Flavor) (filename : String) (t : RegexTest) : IO (Nat × Nat × Nat) := do if checkFlagIsFalse t.compiles then - if checkCompiles t + if checkCompiles flavor t then IO.println s!"RegexTest: {t}" IO.println s!" should not compile" pure (0, 1, 0) else pure (1, 0, 0) - else if ignoreTest t - then - pure (0, 0, 1) + else if ignoreTest t then pure (0, 0, 1) + else if List.contains ignoredTests t.name then pure (0, 0, 1) else - match captures t with + match captures flavor t with | Except.ok result => if result.size = 0 then @@ -222,13 +283,15 @@ def testItem (filename : String) (t : RegexTest) : IO (Nat × Nat × Nat) := do IO.println s!" match different, expected {t.matches}, actual {capturesToString result}" pure (0, 1, 0) | Except.error e => + if t.matches.size = 0 then pure (0, 0, 1) else + if List.contains ignoredErrors e then pure (0, 0, 1) else IO.println s!"RegexTest{filename}: {t}" IO.println s!" error {e}" pure (0, 1, 0) -def testItems (filename : String) (items : Array RegexTest) : IO (Nat × Nat× Nat) := do +def testItems (flavor : Syntax.Flavor) (filename : String) (items : Array RegexTest) : IO (Nat × Nat× Nat) := do items |> Array.foldlM (init := (0, 0, 0)) (fun (succeeds, failures, ignored) RegexTest => do - let (succeed, failure, ignore) ← testItem filename RegexTest + let (succeed, failure, ignore) ← testItem flavor filename RegexTest pure (succeeds + succeed, failures + failure, ignore + ignored)) end RegexTest diff --git a/test/Test.lean b/test/Test.lean index 3e75e9b..2c774e0 100644 --- a/test/Test.lean +++ b/test/Test.lean @@ -7,24 +7,34 @@ import Test.Compiler import RegexTest import TomlLoader +import PcreLoader open Lean System open Regex -def test (path : FilePath): IO (Nat × Nat × Nat) := do +def testToml (path : FilePath) (filename : String) (flavor : Syntax.Flavor) (tests : Array RegexTest) : IO (Nat × Nat × Nat) := do + let (succeeds, failures, ignored) ← RegexTest.testItems flavor filename tests + IO.println s!"succeeds {succeeds} failures {failures} ignored {ignored} in file {path}" + pure (succeeds, failures, ignored) + +def testRustFile (path : FilePath) : IO (Nat × Nat × Nat) := do let filename : String := path.fileName.getD "" if #["no-unicode.toml", "regex-lite.toml", "utf8.toml"].contains filename then pure (0, 0, 0) else - let tests ← Loader.loadToml path - let (succeeds, failures, ignored) ← RegexTest.testItems filename tests - IO.println s!"succeeds {succeeds} failures {failures} ignored {ignored} in file {path}" - pure (succeeds, failures, ignored) + let tests ← Loader.Toml.load path + testToml path filename Syntax.Flavor.Rust tests + +def testPcreFile (path : FilePath) : IO (Nat × Nat × Nat) := do + let filename : String := path.fileName.getD "" + let tests := (← Loader.Pcre.load path) |> Loader.Pcre.toRegexTestArray + testToml path filename Syntax.Flavor.Pcre tests def summary (arr : Array (Nat × Nat × Nat)) : IO UInt32 := do let (succeeds, failures, ignored) := arr |> Array.foldl (fun acc v => (acc.1+v.1, acc.2.1+v.2.1, acc.2.2+v.2.2) ) (0, 0, 0) IO.println s!"succeeds {succeeds} failures {failures} ignored {ignored} total" + if failures > 0 then IO.eprintln s!"succeeds {succeeds} failures {failures} ignored {ignored} total" pure (if failures > 0 then 1 else 0) def testAll (path : FilePath): IO UInt32 := do @@ -32,7 +42,7 @@ def testAll (path : FilePath): IO UInt32 := do then (← System.FilePath.walkDir path) |> Array.filter (fun f => f.toString.endsWith "toml") - |> Array.mapM (fun file => test file) + |> Array.mapM (fun file => testRustFile file) |> fun arr => do summary (← arr) else IO.println s!"no such directory '{path}'" @@ -42,11 +52,12 @@ def main (args : List String): IO UInt32 := do let exitcode ← try match args with - | [] => pure <| ← testAll "testdata" - | ["--toml", path] => pure <| ← summary #[← test path] + | [] => pure <| ← testAll "testdata/rust" + | ["--pcre", path] => pure <| ← summary #[← testPcreFile path] + | ["--toml", path] => pure <| ← summary #[← testRustFile path] | ["--all", path] => pure <| ← testAll path | _ => - IO.println s!"usage: Test [--toml ] [--all path]" + IO.println s!"usage: Test [--toml | --pcre] [--all path]" pure 1 catch e => IO.println s!"Error: {e}" diff --git a/test/Test/Ast.lean b/test/Test/Ast.lean index bd89059..ae91b6c 100644 --- a/test/Test/Ast.lean +++ b/test/Test/Ast.lean @@ -61,18 +61,18 @@ private def «astOf'(a)'» : Ast := (GroupKind.CaptureIndex 1) (Ast.Literal ⟨String.toSpan "(a)" 1 2, LiteralKind.Verbatim, 'a'⟩)) -example : (parse "a" |> toString) = s!"{astOf'a'}" := by native_decide +example : (parse "a" Syntax.Flavor.Rust |> toString) = s!"{astOf'a'}" := by native_decide -example : (parse "a?" |> toString) = s!"{astOf'a?'}" := by native_decide +example : (parse "a?" Syntax.Flavor.Rust |> toString) = s!"{astOf'a?'}" := by native_decide -example : (parse "ab" |> toString) = s!"{astOf'ab'}" := by native_decide +example : (parse "ab" Syntax.Flavor.Rust |> toString) = s!"{astOf'ab'}" := by native_decide -example : (parse "[a]" |> toString) = s!"{«astOf'[a]'»}" := by native_decide +example : (parse "[a]" Syntax.Flavor.Rust |> toString) = s!"{«astOf'[a]'»}" := by native_decide -example : (parse "[a-b]" |> toString) = s!"{«astOf'[a-b]'»}" := by native_decide +example : (parse "[a-b]" Syntax.Flavor.Rust |> toString) = s!"{«astOf'[a-b]'»}" := by native_decide -example : (parse "a|b" |> toString) = s!"{«astOf'a|b'»}" := by native_decide +example : (parse "a|b" Syntax.Flavor.Rust |> toString) = s!"{«astOf'a|b'»}" := by native_decide -example : (parse "(a)" |> toString) = s!"{«astOf'(a)'»}" := by native_decide +example : (parse "(a)" Syntax.Flavor.Rust |> toString) = s!"{«astOf'(a)'»}" := by native_decide end Test.Ast diff --git a/test/Test/Compiler.lean b/test/Test/Compiler.lean index 00b5f36..4ebd2f1 100644 --- a/test/Test/Compiler.lean +++ b/test/Test/Compiler.lean @@ -127,7 +127,7 @@ error: failed to parse pattern a[, error: unclosed character class #guard_msgs in def re := regex% "a[" -example : NFA.Checked.toString nfaOf'a'Checked = nfaOf'a'.toString := by native_decide +example : toString nfaOf'a'Checked = toString nfaOf'a' := by native_decide example : toString (regex% "a").nfa = nfaOf'a'.toString := by native_decide @@ -145,4 +145,24 @@ example : toString (regex% "(a)").nfa = «nfaOf'(a)'».toString := by native_dec example : toString (regex% "[a]{0,2}").nfa = «nfaOf'[a]{0,2}'».toString := by native_decide +private def caputesOf (c : Char) : Option Captures := some ⟨c.toString.toSubstring , #[]⟩ + +example : toString (Regex.captures "a" (regex% "a")) = toString (caputesOf 'a') := by native_decide + +example : toString (Regex.captures "ab" (regex% "a(?=b)")) = toString (caputesOf 'a') := by native_decide + +example : regex% "a(?=b)" |> Regex.captures "ac" |>.isNone := by native_decide + +example : toString (Regex.captures "ac" (regex% "a(?!b)")) = toString (caputesOf 'a') := by native_decide + +example : regex% "a(?!b)" |> Regex.captures "ab" |>.isNone := by native_decide + +private def fullMatch (captures : Option Captures) : String := + match captures with | some captures => captures.fullMatch.toString | none => "" + +example : (fullMatch <| Regex.captures + "∀ (n : Nat), 0 ≤ n" + (regex% r"^\p{Math}\s*(.(?<=\()([a-z])[^,]+),\s*(\p{Nd})\s*(\p{Math})\s*\2$")) + = "∀ (n : Nat), 0 ≤ n" := by native_decide + end Test.Compiler diff --git a/test/Test/Hir.lean b/test/Test/Hir.lean index 6de8237..a3ad4a9 100644 --- a/test/Test/Hir.lean +++ b/test/Test/Hir.lean @@ -22,7 +22,7 @@ private def toString (x : Except String Hir) : String := | Except.error e => s!"Error {e}" private def build (s : String) : Except String Hir := do - let ast ← Syntax.AstItems.parse s + let ast ← Syntax.AstItems.parse s Syntax.Flavor.Rust let hir ← Syntax.translate default ast Except.ok hir diff --git a/test/TomlLoader.lean b/test/TomlLoader.lean index 82c131b..e7564b5 100644 --- a/test/TomlLoader.lean +++ b/test/TomlLoader.lean @@ -7,7 +7,9 @@ import RegexTest open Lean System Lake Lake.Toml -namespace Loader +namespace Loader.Toml + +/-- load toml files from Rust testdata -/ protected def Span.decodeToml (v : Value) (s := Syntax.missing) : Except (Array DecodeError) (Option RegexTest.Span) := @@ -17,7 +19,7 @@ protected def Span.decodeToml (v : Value) (s := Syntax.missing) | #[] => pure none | #[a, b] => match a, b with - | .integer _ a, .integer _ b => pure (RegexTest.Span.mk a.toNat b.toNat) + | .integer _ a, .integer _ b => pure (RegexTest.Span.mk a.toNat b.toNat none) | _, _ => Except.error #[DecodeError.mk s s!"integer array expected {v}"] | _ => Except.error #[DecodeError.mk s s!"array size 0 or 2 expected {v}"] | _ => @@ -95,8 +97,10 @@ protected def RegexTest.decodeToml (t : Table) let «match-kind» : Option String ← t.tryDecode? `«match-kind» let «search-kind» : Option String ← t.tryDecode? `«search-kind» let «line-terminator» : Option String ← t.tryDecode? `«line-terminator» + let «only-full-match» : Option Bool ← t.tryDecode? `«only-full-match» return {name, regex, haystack, «matches», bounds, «match-limit», anchored, «case-insensitive», - unescape, compiles, unicode, utf8, «match-kind», «search-kind», «line-terminator» } + unescape, compiles, unicode, utf8, «match-kind», «search-kind», «line-terminator», + «only-full-match» } instance : DecodeToml RegexTest := ⟨fun v => do RegexTest.decodeToml (← v.decodeTable)⟩ @@ -111,7 +115,7 @@ nonrec def parseToml (table : Table) (tomlFile : FilePath) : IO $ Array RegexTes throw $ .userError s!"decode errors in {tomlFile}\n{msgs}" /-- load testdata toml files of Rust Regex crate -/ -nonrec def loadToml (tomlFile : FilePath) : IO $ Array RegexTest := do +nonrec def load (tomlFile : FilePath) : IO $ Array RegexTest := do let fileName := tomlFile.fileName.getD tomlFile.toString let input ← match (← IO.FS.readBinFile tomlFile |>.toBaseIO) with @@ -129,4 +133,4 @@ nonrec def loadToml (tomlFile : FilePath) : IO $ Array RegexTest := do (fun s msg => s ++ s!"error at {msg.fileName} {msg.pos}") throw $ .userError s!"{msgs}" -end Loader +end Loader.Toml diff --git a/testdata/pcre/create-json.sh b/testdata/pcre/create-json.sh new file mode 100755 index 0000000..b9cab06 --- /dev/null +++ b/testdata/pcre/create-json.sh @@ -0,0 +1,12 @@ +#! /bin/sh + +# create json from perltest.sh + +if [ $# -eq 0 ] ; then + echo "usage: create-json.sh filename " + exit 1 +fi + +FILE=$1 + +./perltest.sh -json ${FILE} | grep '##' | sed 's/##//' | jq 'del(recurse | select(. == {}))' diff --git a/testdata/pcre/perltest.sh b/testdata/pcre/perltest.sh new file mode 100755 index 0000000..28afcce --- /dev/null +++ b/testdata/pcre/perltest.sh @@ -0,0 +1,438 @@ +#! /bin/sh + +# Script for testing regular expressions with perl to check that PCRE2 handles +# them the same. For testing with different versions of Perl, if the first +# argument is -perl then the second is taken as the Perl command to use, and +# both are then removed. If the next argument is "-w", Perl is called with +# "-w", which turns on its warning mode. +# +# The Perl code has to have "use utf8" and "require Encode" at the start when +# running UTF-8 tests, but *not* for non-utf8 tests. (The "require" would +# actually be OK for non-utf8-tests, but is not always installed, so this way +# the script will always run for these tests.) +# +# The desired effect is achieved by making this a shell script that passes the +# Perl script to Perl through a pipe. If the next argument is "-utf8", a +# suitable prefix is set up. +# +# The remaining arguments, if any, are passed to Perl. They are an input file +# and an output file. If there is one argument, the output is written to +# STDOUT. If Perl receives no arguments, it opens /dev/tty as input, and writes +# output to STDOUT. (I haven't found a way of getting it to use STDIN, because +# of the contorted piping input.) + +perl=perl +perlarg='' +prefix='' + +if [ $# -gt 1 -a "$1" = "-perl" ] ; then + shift + perl=$1 + shift +fi + +if [ $# -gt 0 -a "$1" = "-w" ] ; then + perlarg="-w" + shift +fi + +if [ $# -gt 0 -a "$1" = "-utf8" ] ; then + prefix="use utf8; require Encode;" + shift +fi + +if [ $# -gt 0 -a "$1" = "-json" ] ; then + prefix="\$json = 1;" + shift +fi + +# The Perl script that follows has a similar specification to pcre2test, and so +# can be given identical input, except that input patterns can be followed only +# by Perl's lower case modifiers and certain other pcre2test modifiers that are +# either handled or ignored: +# +# aftertext interpreted as "print $' afterwards" +# afteralltext ignored +# dupnames ignored (Perl always allows) +# jitstack ignored +# mark show mark information +# no_auto_possess ignored +# no_start_optimize insert (??{""}) at pattern start (disables optimizing) +# -no_start_optimize ignored +# subject_literal does not process subjects for escapes +# ucp sets Perl's /u modifier +# utf invoke UTF-8 functionality +# +# Comment lines are ignored. The #pattern command can be used to set modifiers +# that will be added to each subsequent pattern, after any modifiers it may +# already have. NOTE: this is different to pcre2test where #pattern sets +# defaults which can be overridden on individual patterns. The #subject command +# may be used to set or unset a default "mark" modifier for data lines. This is +# the only use of #subject that is supported. The #perltest, #forbid_utf, and +# #newline_default commands, which are needed in the relevant pcre2test files, +# are ignored. Any other #-command is ignored, with a warning message. +# +# The pattern lines should use only / as the delimiter. The other characters +# that pcre2test supports cause problems with this script. +# +# The data lines must not have any pcre2test modifiers. Unless +# "subject_literal" is on the pattern, data lines are processed as +# Perl double-quoted strings, so if they contain " $ or @ characters, these +# have to be escaped. For this reason, all such characters in the +# Perl-compatible testinput1 and testinput4 files are escaped so that they can +# be used for perltest as well as for pcre2test. The output from this script +# should be same as from pcre2test, apart from the initial identifying banner. +# +# The other testinput files are not suitable for feeding to perltest.sh, +# because they make use of the special modifiers that pcre2test uses for +# testing features of PCRE2. Some of these files also contain malformed regular +# expressions, in order to check that PCRE2 diagnoses them correctly. + +(echo "$prefix" ; cat <<'PERLEND' + +# The alpha assertions currently give warnings even when -w is not specified. + +no warnings "experimental::alpha_assertions"; +no warnings "experimental::script_run"; + +# Function for turning a string into a string of printing chars. + +sub pchars { +use JSON::PP; +my($t) = ""; +if ($utf8) + { + @p = unpack('U*', $_[0]); + foreach $c (@p) + { + if ($c >= 32 && $c < 127) { $t .= chr $c; } + else { $t .= sprintf("\\x{%02x}", $c); + } + } + } +else + { + foreach $c (split(//, $_[0])) + { + if (ord $c >= 32 && ord $c < 127) { $t .= $c; } + else { $t .= sprintf("\\x%02x", ord $c); } + } + } +$t; +} + + +# Read lines from a named file or stdin and write to a named file or stdout; +# lines consist of a regular expression, in delimiters and optionally followed +# by options, followed by a set of test data, terminated by an empty line. + +# Sort out the input and output files + +if (@ARGV > 0) + { + open(INFILE, "<$ARGV[0]") || die "Failed to open $ARGV[0]\n"; + $infile = "INFILE"; + $interact = 0; + } +else + { + open(INFILE, " 1) + { + open(OUTFILE, ">$ARGV[1]") || die "Failed to open $ARGV[1]\n"; + $outfile = "OUTFILE"; + } +else { $outfile = "STDOUT"; } + +printf($outfile "Perl $^V\n\n"); + +$extra_modifiers = ""; +$default_show_mark = 0; + +$jsonMarker = "##"; +printf $outfile "${jsonMarker}[\n" if $json; + +# Main loop + +NEXT_RE: +for (;;) + { + printf " re> " if $interact; + last if ! ($_ = <$infile>); + printf $outfile "$_" if ! $interact; + next if ($_ =~ /^\s*$/ || $_ =~ /^#[\s!]/); + + # A few of pcre2test's #-commands are supported, or just ignored. Any others + # cause an error. + + if ($_ =~ /^#pattern(.*)/) + { + $extra_modifiers = $1; + chomp($extra_modifiers); + $extra_modifiers =~ s/\s+$//; + next; + } + elsif ($_ =~ /^#subject(.*)/) + { + $mod = $1; + chomp($mod); + $mod =~ s/\s+$//; + if ($mod =~ s/(-?)mark,?//) + { + $minus = $1; + $default_show_mark = ($minus =~ /^$/); + } + if ($mod !~ /^\s*$/) + { + printf $outfile "** Warning: \"$mod\" in #subject ignored\n"; + } + next; + } + elsif ($_ =~ /^#/) + { + if ($_ !~ /^#newline_default|^#perltest|^#forbid_utf/) + { + printf $outfile "** Warning: #-command ignored: %s", $_; + } + next; + } + + $pattern = $_; + + while ($pattern !~ /^\s*(.).*\1/s) + { + printf " > " if $interact; + last if ! ($_ = <$infile>); + printf $outfile "$_" if ! $interact; + $pattern .= $_; + } + + chomp($pattern); + $pattern =~ s/\s+$//; + + # Split the pattern from the modifiers and adjust them as necessary. + + $pattern =~ /^\s*((.).*\2)(.*)$/s; + $pat = $1; + $del = $2; + $mod = "$3,$extra_modifiers"; + $mod =~ s/^,\s*//; + + # The private "aftertext" modifier means "print $' afterwards". + + $showrest = ($mod =~ s/aftertext,?//); + + # The "subject_literal" modifier disables escapes in subjects. + + $subject_literal = ($mod =~ s/subject_literal,?//); + + # "allaftertext" is used by pcre2test to print remainders after captures + + $mod =~ s/allaftertext,?//; + + # Detect utf + + $utf8 = $mod =~ s/utf,?//; + + # Remove "dupnames". + + $mod =~ s/dupnames,?//; + + # Remove "jitstack". + + $mod =~ s/jitstack=\d+,?//; + + # The "mark" modifier requests checking of MARK data */ + + $show_mark = $default_show_mark | ($mod =~ s/mark,?//); + + # "ucp" asks pcre2test to set PCRE2_UCP; change this to /u for Perl + + $mod =~ s/ucp,?/u/; + + # Remove "no_auto_possess". + + $mod =~ s/no_auto_possess,?//; + + # Use no_start_optimize (disable PCRE2 start-up optimization) to disable Perl + # optimization by inserting (??{""}) at the start of the pattern. We may + # also encounter -no_start_optimize from a #pattern setting. + + $mod =~ s/-no_start_optimize,?//; + + if ($mod =~ s/no_start_optimize,?//) { $pat =~ s/$del/$del(??{""})/; } + + # Add back retained modifiers and check that the pattern is valid. + + $mod =~ s/,//g; + $pattern = "$pat$mod"; + + eval "\$_ =~ ${pattern}"; + if ($@) + { + printf $outfile "Error: $@"; + if (! $interact) + { + for (;;) + { + last if ! ($_ = <$infile>); + last if $_ =~ /^\s*$/; + } + } + next NEXT_RE; + } + + # If the /g modifier is present, we want to put a loop round the matching; + # otherwise just a single "if". + + $cmd = ($pattern =~ /g[a-z]*\s*$/)? "while" : "if"; + + # If the pattern is actually the null string, Perl uses the most recently + # executed (and successfully compiled) regex is used instead. This is a + # nasty trap for the unwary! The PCRE2 test suite does contain null strings + # in places - if they are allowed through here all sorts of weird and + # unexpected effects happen. To avoid this, we replace such patterns with + # a non-null pattern that has the same effect. + + $pattern = "/(?#)/$2" if ($pattern =~ /^(.)\1(.*)$/); + + # Read data lines and test them + + $match_expected = 1; + + for (;;) + { + printf "data> " if $interact; + last NEXT_RE if ! ($_ = <$infile>); + chomp; + printf $outfile "%s", "$_\n" if ! $interact; + + s/\s+$//; # Remove trailing space + s/^\s+//; # Remove leading space + + last if ($_ eq ""); + if ($_ =~ /^\\=/) { + $match_expected = 0; + }; + next if $_ =~ /^\\=(?:\s|$)/; # Comment line + + printf $outfile "%s", "${jsonMarker}{\n" if $json; + printf $outfile "%s", "${jsonMarker} \"matchExpected\": $match_expected,\n" if $json; + $mypattern = encode_json $pattern; + printf $outfile "%s", "${jsonMarker} \"pattern\": $mypattern,\n" if $json; + $myhaystack = encode_json $_; + printf $outfile "%s", "${jsonMarker} \"haystack\": $myhaystack,\n" if $json; + + $match_expected = 1; + + if ($subject_literal) + { + $x = $_; + } + else + { + $x = eval "\"$_\""; # To get escapes processed + } + + # Empty array for holding results, ensure $REGERROR and $REGMARK are + # unset, then do the matching. + + @subs = (); + + $pushes = "push \@subs,\$&;" . + "push \@subs,\$1;" . + "push \@subs,\$2;" . + "push \@subs,\$3;" . + "push \@subs,\$4;" . + "push \@subs,\$5;" . + "push \@subs,\$6;" . + "push \@subs,\$7;" . + "push \@subs,\$8;" . + "push \@subs,\$9;" . + "push \@subs,\$10;" . + "push \@subs,\$11;" . + "push \@subs,\$12;" . + "push \@subs,\$13;" . + "push \@subs,\$14;" . + "push \@subs,\$15;" . + "push \@subs,\$16;" . + "push \@subs,\$'; }"; + + undef $REGERROR; + undef $REGMARK; + + $nloop = 0; + + eval "${cmd} (\$x =~ ${pattern}) {" . $pushes; + + if ($@) + { + printf $outfile "Error: $@\n"; + next NEXT_RE; + } + elsif (scalar(@subs) == 0) + { + printf $outfile "No match"; + if ($show_mark && defined $REGERROR && $REGERROR != 1) + { printf $outfile (", mark = %s", &pchars($REGERROR)); } + printf $outfile "\n"; + printf $outfile "${jsonMarker} \"noMatch\": true\n${jsonMarker}},\n" if $json; + } + else + { + printf $outfile "${jsonMarker} \"match\": [\n" if $json; + while (scalar(@subs) != 0) + { + printf $outfile (" 0: %s\n", &pchars($subs[0])); + $match = encode_json &pchars($subs[0]); + printf $outfile "${jsonMarker} {\"match\": $match\n" if $json; + + printf $outfile (" 0+ %s\n", &pchars($subs[17])) if $showrest; + $last_printed = 0; + for ($i = 1; $i <= 16; $i++) + { + if (defined $subs[$i]) + { + while ($last_printed++ < $i-1) + { printf $outfile ("%2d: \n", $last_printed); } + printf $outfile ("%2d: %s\n", $i, &pchars($subs[$i])); + $match = encode_json &pchars($subs[$i]); + printf $outfile ("${jsonMarker} ,\"group%d\": %s\n", $i, $match) if $json; + $last_printed = $i; + } + } + splice(@subs, 0, 18); + printf $outfile "${jsonMarker} },\n" if $json; + } + + printf $outfile "${jsonMarker} {}]},\n" if $json; + + # It seems that $REGMARK is not marked as UTF-8 even when use utf8 is + # set and the input pattern was a UTF-8 string. We can, however, force + # it to be so marked. + + if ($show_mark && defined $REGMARK && $REGMARK != 1) + { + $xx = $REGMARK; + $xx = Encode::decode_utf8($xx) if $utf8; + printf $outfile ("MK: %s\n", &pchars($xx)); + } + } + } + } + +# By closing OUTFILE explicitly, we avoid a Perl warning in -w mode +# "main::OUTFILE" used only once". + +printf $outfile "${jsonMarker} {}]\n" if $json; + +close(OUTFILE) if $outfile eq "OUTFILE"; + +PERLEND +) | $perl $perlarg - $@ + +# End diff --git a/testdata/pcre/readme.md b/testdata/pcre/readme.md new file mode 100644 index 0000000..788a7b1 --- /dev/null +++ b/testdata/pcre/readme.md @@ -0,0 +1,10 @@ +# PCRE2 Testdata + +The Regex library is tested with the [testdata](https://github.com/PCRE2Project/pcre2/tree/master) +of PCRE2 library. + +* testinput1 is from [PCRE2 library](https://github.com/PCRE2Project/pcre2/blob/master/testdata/testinput1), +* tests for variable length positive lookbehind are removed from testinput1, +* perltest.sh is from [PCRE2 library](https://github.com/PCRE2Project/pcre2/blob/master/perltest.sh), +* perltest.sh is slightly changed to generate json output, +* json is generated with the cmd *./create-json.sh testinput1 > testresult1.json*. diff --git a/testdata/pcre/testinput1 b/testdata/pcre/testinput1 new file mode 100644 index 0000000..0ea7a51 --- /dev/null +++ b/testdata/pcre/testinput1 @@ -0,0 +1,6259 @@ +# This set of tests is for features that are compatible with all versions of +# Perl >= 5.10, in non-UTF mode. It should run clean for the 8-bit, 16-bit, and +# 32-bit PCRE libraries, and also using the perltest.sh script. + +# WARNING: Use only / as the pattern delimiter. Although pcre2test supports +# a number of delimiters, all those other than / give problems with the +# perltest.sh script. + +#forbid_utf +#newline_default lf any anycrlf +#perltest + +/the quick brown fox/ + the quick brown fox + What do you know about the quick brown fox? +\= Expect no match + The quick brown FOX + What do you know about THE QUICK BROWN FOX? + +/The quick brown fox/i + the quick brown fox + The quick brown FOX + What do you know about the quick brown fox? + What do you know about THE QUICK BROWN FOX? + +/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/ + abcd\t\n\r\f\a\e9;\$\\?caxyz + +/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/ + abxyzpqrrrabbxyyyypqAzz + abxyzpqrrrabbxyyyypqAzz + aabxyzpqrrrabbxyyyypqAzz + aaabxyzpqrrrabbxyyyypqAzz + aaaabxyzpqrrrabbxyyyypqAzz + abcxyzpqrrrabbxyyyypqAzz + aabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypAzz + aaabcxyzpqrrrabbxyyyypqAzz + aaabcxyzpqrrrabbxyyyypqqAzz + aaabcxyzpqrrrabbxyyyypqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqAzz + aaabcxyzpqrrrabbxyyyypqqqqqqAzz + aaaabcxyzpqrrrabbxyyyypqAzz + abxyzzpqrrrabbxyyyypqAzz + aabxyzzzpqrrrabbxyyyypqAzz + aaabxyzzzzpqrrrabbxyyyypqAzz + aaaabxyzzzzpqrrrabbxyyyypqAzz + abcxyzzpqrrrabbxyyyypqAzz + aabcxyzzzpqrrrabbxyyyypqAzz + aaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyyypqAzz + aaabcxyzpqrrrabbxyyyypABzz + aaabcxyzpqrrrabbxyyyypABBzz + >>>aaabxyzpqrrrabbxyyyypqAzz + >aaaabxyzpqrrrabbxyyyypqAzz + >>>>abcxyzpqrrrabbxyyyypqAzz +\= Expect no match + abxyzpqrrabbxyyyypqAzz + abxyzpqrrrrabbxyyyypqAzz + abxyzpqrrrabxyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz + aaaabcxyzzzzpqrrrabbbxyyypqAzz + aaabcxyzpqrrrabbxyyyypqqqqqqqAzz + +/^(abc){1,2}zz/ + abczz + abcabczz +\= Expect no match + zz + abcabcabczz + >>abczz + +/^(b+?|a){1,2}?c/ + bc + bbc + bbbc + bac + bbac + aac + abbbbbbbbbbbc + bbbbbbbbbbbac +\= Expect no match + aaac + abbbbbbbbbbbac + +/^(b+|a){1,2}c/ + bc + bbc + bbbc + bac + bbac + aac + abbbbbbbbbbbc + bbbbbbbbbbbac +\= Expect no match + aaac + abbbbbbbbbbbac + +/^(ba|b*){1,2}?bc/ + babc + bbabc + bababc +\= Expect no match + bababbc + babababc + +/^\ca\cA\c[;\c:/ + \x01\x01\e;z + +/^[ab\]cde]/ + athing + bthing + ]thing + cthing + dthing + ething +\= Expect no match + fthing + [thing + \\thing + +/^[]cde]/ + ]thing + cthing + dthing + ething +\= Expect no match + athing + fthing + +/^[^ab\]cde]/ + fthing + [thing + \\thing +\= Expect no match + athing + bthing + ]thing + cthing + dthing + ething + +/^[^]cde]/ + athing + fthing +\= Expect no match + ]thing + cthing + dthing + ething + +/^\/ + + +/^/ + + +/^[0-9]+$/ + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 100 +\= Expect no match + abc + +/^.*nter/ + enter + inter + uponter + +/^xxx[0-9]+$/ + xxx0 + xxx1234 +\= Expect no match + xxx + +/^.+[0-9][0-9][0-9]$/ + x123 + x1234 + xx123 + 123456 +\= Expect no match + 123 + +/^.+?[0-9][0-9][0-9]$/ + x123 + x1234 + xx123 + 123456 +\= Expect no match + 123 + +/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/ + abc!pqr=apquxz.ixr.zzz.ac.uk +\= Expect no match + !pqr=apquxz.ixr.zzz.ac.uk + abc!=apquxz.ixr.zzz.ac.uk + abc!pqr=apquxz:ixr.zzz.ac.uk + abc!pqr=apquxz.ixr.zzz.ac.ukk + +/:/ + Well, we need a colon: somewhere +\= Expect no match + Fail without a colon + +/([\da-f:]+)$/i + 0abc + abc + fed + E + :: + 5f03:12C0::932e + fed def + Any old stuff +\= Expect no match + 0zzz + gzzz + fed\x20 + Any old rubbish + +/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ + .1.2.3 + A.12.123.0 +\= Expect no match + .1.2.3333 + 1.2.3 + 1234.2.3 + +/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/ + 1 IN SOA non-sp1 non-sp2( + 1 IN SOA non-sp1 non-sp2 ( +\= Expect no match + 1IN SOA non-sp1 non-sp2( + +/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/ + a. + Z. + 2. + ab-c.pq-r. + sxk.zzz.ac.uk. + x-.y-. +\= Expect no match + -abc.peq. + +/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/ + *.a + *.b0-a + *.c3-b.c + *.c-a.b-c +\= Expect no match + *.0 + *.a- + *.a-b.c- + *.c-a.0-c + +/^(?=ab(de))(abd)(e)/ + abde + +/^(?!(ab)de|x)(abd)(f)/ + abdf + +/^(?=(ab(cd)))(ab)/ + abcd + +/^[\da-f](\.[\da-f])*$/i + a.b.c.d + A.B.C.D + a.b.c.1.2.3.C + +/^\".*\"\s*(;.*)?$/ + \"1234\" + \"abcd\" ; + \"\" ; rhubarb +\= Expect no match + \"1234\" : things + +/^$/ + \ +\= Expect no match + A non-empty line + +/ ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/x + ab c +\= Expect no match + abc + ab cde + +/(?x) ^ a (?# begins with a) b\sc (?# then b c) $ (?# then end)/ + ab c +\= Expect no match + abc + ab cde + +/^ a\ b[c ]d $/x + a bcd + a b d +\= Expect no match + abcd + ab d + +/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/ + abcdefhijklm + +/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/ + abcdefhijklm + +/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/ + a+ Z0+\x08\n\x1d\x12 + +/^[.^$|()*+?{,}]+/ + .^\$(*+)|{?,?} + +/^a*\w/ + z + az + aaaz + a + aa + aaaa + a+ + aa+ + +/^a*?\w/ + z + az + aaaz + a + aa + aaaa + a+ + aa+ + +/^a+\w/ + az + aaaz + aa + aaaa + aa+ + +/^a+?\w/ + az + aaaz + aa + aaaa + aa+ + +/^\d{8}\w{2,}/ + 1234567890 + 12345678ab + 12345678__ +\= Expect no match + 1234567 + +/^[aeiou\d]{4,5}$/ + uoie + 1234 + 12345 + aaaaa +\= Expect no match + 123456 + +/^[aeiou\d]{4,5}?/ + uoie + 1234 + 12345 + aaaaa + 123456 + +/\A(abc|def)=(\1){2,3}\Z/ + abc=abcabc + def=defdefdef +\= Expect no match + abc=defdef + +/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/ + abcdefghijkcda2 + abcdefghijkkkkcda2 + +/(cat(a(ract|tonic)|erpillar)) \1()2(3)/ + cataract cataract23 + catatonic catatonic23 + caterpillar caterpillar23 + + +/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/ + From abcd Mon Sep 01 12:33:02 1997 + +/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/ + From abcd Mon Sep 01 12:33:02 1997 + From abcd Mon Sep 1 12:33:02 1997 +\= Expect no match + From abcd Sep 01 12:33:02 1997 + +/^12.34/s + 12\n34 + 12\r34 + +/\w+(?=\t)/ + the quick brown\t fox + +/foo(?!bar)(.*)/ + foobar is foolish see? + +/(?:(?!foo)...|^.{0,2})bar(.*)/ + foobar crowbar etc + barrel + 2barrel + A barrel + +/^(\D*)(?=\d)(?!123)/ + abc456 +\= Expect no match + abc123 + +/^1234(?# test newlines + inside)/ + 1234 + +/^1234 #comment in extended re + /x + 1234 + +/#rhubarb + abcd/x + abcd + +/^abcd#rhubarb/x + abcd + +/^(a)\1{2,3}(.)/ + aaab + aaaab + aaaaab + aaaaaab + +/(?!^)abc/ + the abc +\= Expect no match + abc + +/(?=^)abc/ + abc +\= Expect no match + the abc + +/^[ab]{1,3}(ab*|b)/ + aabbbbb + +/^[ab]{1,3}?(ab*|b)/ + aabbbbb + +/^[ab]{1,3}?(ab*?|b)/ + aabbbbb + +/^[ab]{1,3}(ab*?|b)/ + aabbbbb + +/ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional leading comment +(?: (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # one word, optionally followed by.... +(?: +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] | # atom and space parts, or... +\( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) | # comments, or... + +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +# quoted strings +)* +< (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # leading < +(?: @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* + +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* , (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +)* # further okay, if led by comma +: # closing colon +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* )? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) # initial word +(?: (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +" (?: # opening quote... +[^\\\x80-\xff\n\015"] # Anything except backslash and quote +| # or +\\ [^\x80-\xff] # Escaped something (something != CR) +)* " # closing quote +) )* # further okay, if led by a period +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* @ (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # initial subdomain +(?: # +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* \. # if led by a period... +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* (?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| \[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) # ...further okay +)* +# address spec +(?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* > # trailing > +# name and address +) (?: [\040\t] | \( +(?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] | \( (?: [^\\\x80-\xff\n\015()] | \\ [^\x80-\xff] )* \) )* +\) )* # optional trailing comment +/x + Alan Other + + user\@dom.ain + \"A. Other\" (a comment) + A. Other (a comment) + \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay + A missing angle @,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address +| # or +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +# leading word +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # "normal" atoms and or spaces +(?: +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +| +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +) # "special" comment or quoted string +[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] * # more "normal" +)* +< +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# < +(?: +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +(?: , +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +)* # additional domains +: +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)? # optional route +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +# Atom +| # or +" # " +[^\\\x80-\xff\n\015"] * # normal +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015"] * )* # ( special normal* )* +" # " +# Quoted string +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# additional words +)* +@ +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +(?: +\. +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +(?: +[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+ # some number of atom characters... +(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom +| +\[ # [ +(?: [^\\\x80-\xff\n\015\[\]] | \\ [^\x80-\xff] )* # stuff +\] # ] +) +[\040\t]* # Nab whitespace. +(?: +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: # ( +(?: \\ [^\x80-\xff] | +\( # ( +[^\\\x80-\xff\n\015()] * # normal* +(?: \\ [^\x80-\xff] [^\\\x80-\xff\n\015()] * )* # (special normal*)* +\) # ) +) # special +[^\\\x80-\xff\n\015()] * # normal* +)* # )* +\) # ) +[\040\t]* )* # If comment found, allow more spaces. +# optional trailing comments +)* +# address spec +> # > +# name and address +) +/x + Alan Other + + user\@dom.ain + \"A. Other\" (a comment) + A. Other (a comment) + \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay + A missing angle ]{0,})>]{0,})>([\d]{0,}\.)(.*)((
([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is + 43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide + +/a[^a]b/ + acb + a\nb + +/a.b/ + acb +\= Expect no match + a\nb + +/a[^a]b/s + acb + a\nb + +/a.b/s + acb + a\nb + +/^(b+?|a){1,2}?c/ + bac + bbac + bbbac + bbbbac + bbbbbac + +/^(b+|a){1,2}?c/ + bac + bbac + bbbac + bbbbac + bbbbbac + +/(?!\A)x/m + a\bx\n + a\nx\n +\= Expect no match + x\nb\n + +/(A|B)*?CD/ + CD + +/(A|B)*CD/ + CD + +/(AB)*?\1/ + ABABAB + +/(AB)*\1/ + ABABAB + +/(?.*\/)foo/ + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo +\= Expect no match + /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/ + +/(?>(\.\d\d[1-9]?))\d+/ + 1.230003938 + 1.875000282 +\= Expect no match + 1.235 + +/^((?>\w+)|(?>\s+))*$/ + now is the time for all good men to come to the aid of the party +\= Expect no match + this is not a line with only words and spaces! + +/(\d+)(\w)/ + 12345a + 12345+ + +/((?>\d+))(\w)/ + 12345a +\= Expect no match + 12345+ + +/(?>a+)b/ + aaab + +/((?>a+)b)/ + aaab + +/(?>(a+))b/ + aaab + +/(?>b)+/ + aaabbbccc + +/(?>a+|b+|c+)*c/ + aaabbbbccccd + +/((?>[^()]+)|\([^()]*\))+/ + ((abc(ade)ufh()()x + +/\(((?>[^()]+)|\([^()]+\))+\)/ + (abc) + (abc(def)xyz) +\= Expect no match + ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/a(?-i)b/i + ab + Ab +\= Expect no match + aB + AB + +/(a (?x)b c)d e/ + a bcd e +\= Expect no match + a b cd e + abcd e + a bcde + +/(a b(?x)c d (?-x)e f)/ + a bcde f +\= Expect no match + abcdef + +/(a(?i)b)c/ + abc + aBc +\= Expect no match + abC + aBC + Abc + ABc + ABC + AbC + +/a(?i:b)c/ + abc + aBc +\= Expect no match + ABC + abC + aBC + +/a(?i:b)*c/ + aBc + aBBc +\= Expect no match + aBC + aBBC + +/a(?=b(?i)c)\w\wd/ + abcd + abCd +\= Expect no match + aBCd + abcD + +/(?s-i:more.*than).*million/i + more than million + more than MILLION + more \n than Million +\= Expect no match + MORE THAN MILLION + more \n than \n million + +/(?:(?s-i)more.*than).*million/i + more than million + more than MILLION + more \n than Million +\= Expect no match + MORE THAN MILLION + more \n than \n million + +/(?>a(?i)b+)+c/ + abc + aBbc + aBBc +\= Expect no match + Abc + abAb + abbC + +/(?=a(?i)b)\w\wc/ + abc + aBc +\= Expect no match + Ab + abC + aBC + +/(?<=a(?i)b)(\w\w)c/ + abxxc + aBxxc +\= Expect no match + Abxxc + ABxxc + abxxC + +/(?:(a)|b)(?(1)A|B)/ + aA + bB +\= Expect no match + aB + bA + +/^(a)?(?(1)a|b)+$/ + aa + b + bb +\= Expect no match + ab + +# Perl gets this next one wrong if the pattern ends with $; in that case it +# fails to match "12". + +/^(?(?=abc)\w{3}:|\d\d)/ + abc: + 12 + 123 +\= Expect no match + xyz + +/^(?(?!abc)\d\d|\w{3}:)$/ + abc: + 12 +\= Expect no match + 123 + xyz + +/(?(?<=foo)bar|cat)/ + foobar + cat + fcat + focat +\= Expect no match + foocat + +/(?(?a*)*/ + a + aa + aaaa + +/(abc|)+/ + abc + abcabc + abcabcabc + xyz + +/([a]*)*/ + a + aaaaa + +/([ab]*)*/ + a + b + ababab + aaaabcde + bbbb + +/([^a]*)*/ + b + bbbb + aaa + +/([^ab]*)*/ + cccc + abab + +/([a]*?)*/ + a + aaaa + +/([ab]*?)*/ + a + b + abab + baba + +/([^a]*?)*/ + b + bbbb + aaa + +/([^ab]*?)*/ + c + cccc + baba + +/(?>a*)*/ + a + aaabcde + +/((?>a*))*/ + aaaaa + aabbaa + +/((?>a*?))*/ + aaaaa + aabbaa + +/(?(?=[^a-z]+[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) /x + 12-sep-98 + 12-09-98 +\= Expect no match + sep-12-98 + +/(?<=(foo))bar\1/ + foobarfoo + foobarfootling +\= Expect no match + foobar + barfoo + +/(?i:saturday|sunday)/ + saturday + sunday + Saturday + Sunday + SATURDAY + SUNDAY + SunDay + +/(a(?i)bc|BB)x/ + abcx + aBCx + bbx + BBx +\= Expect no match + abcX + aBCX + bbX + BBX + +/^([ab](?i)[cd]|[ef])/ + ac + aC + bD + elephant + Europe + frog + France +\= Expect no match + Africa + +/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/ + ab + aBd + xy + xY + zebra + Zambesi +\= Expect no match + aCD + XY + +/(?<=foo\n)^bar/m + foo\nbar +\= Expect no match + bar + baz\nbar + +/(?<=(?]&/ + <&OUT + +/^(a\1?){4}$/ + aaaaaaaaaa +\= Expect no match + AB + aaaaaaaaa + aaaaaaaaaaa + +/^(a(?(1)\1)){4}$/ + aaaaaaaaaa +\= Expect no match + aaaaaaaaa + aaaaaaaaaaa + +/(?<=a)b/ + ab +\= Expect no match + cb + b + +/(?a+)ab/ + +/(?>a+)b/ + aaab + +/([[:]+)/ + a:[b]: + +/([[=]+)/ + a=[b]= + +/([[.]+)/ + a.[b]. + +/((?>a+)b)/ + aaab + +/(?>(a+))b/ + aaab + +/((?>[^()]+)|\([^()]*\))+/ + ((abc(ade)ufh()()x + +/a\Z/ +\= Expect no match + aaab + a\nb\n + +/b\Z/ + a\nb\n + +/b\z/ + +/b\Z/ + a\nb + +/b\z/ + a\nb + +/^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/ + a + abc + a-b + 0-9 + a.b + 5.6.7 + the.quick.brown.fox + a100.b200.300c + 12-ab.1245 +\= Expect no match + \ + .a + -a + a- + a. + a_b + a.- + a.. + ab..bc + the.quick.brown.fox- + the.quick.brown.fox. + the.quick.brown.fox_ + the.quick.brown.fox+ + +/(?>.*)(?<=(abcd|wxyz))/ + alphabetabcd + endingwxyz +\= Expect no match + a rather long string that doesn't end with one of them + +/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/ + word cat dog elephant mussel cow horse canary baboon snake shark otherword +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark + +/word (?>[a-zA-Z0-9]+ ){0,30}otherword/ +\= Expect no match + word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope + +/(?<=\d{3}(?!999))foo/ + 999foo + 123999foo +\= Expect no match + 123abcfoo + +/(?<=(?!...999)\d{3})foo/ + 999foo + 123999foo +\= Expect no match + 123abcfoo + +/(?<=\d{3}(?!999)...)foo/ + 123abcfoo + 123456foo +\= Expect no match + 123999foo + +/(?<=\d{3}...)(?\s*)=(?>\s*) # find Z)+|A)*/ + ZABCDEFG + +/((?>)+|A)*/ + ZABCDEFG + +/a*/g + abbab + +/[[:space:]]+/ + > \x09\x0a\x0c\x0d\x0b< + +/[[:blank:]]+/ + > \x09\x0a\x0c\x0d\x0b< + +/[\s]+/ + > \x09\x0a\x0c\x0d\x0b< + +/\s+/ + > \x09\x0a\x0c\x0d\x0b< + +/a b/x + ab + +/(?!\A)x/m + a\nxb\n + +/(?!^)x/m +\= Expect no match + a\nxb\n + +/abc\Qabc\Eabc/ + abcabcabc + +/abc\Q(*+|\Eabc/ + abc(*+|abc + +/ abc\Q abc\Eabc/x + abc abcabc +\= Expect no match + abcabcabc + +/abc#comment + \Q#not comment + literal\E/x + abc#not comment\n literal + +/abc#comment + \Q#not comment + literal/x + abc#not comment\n literal + +/abc#comment + \Q#not comment + literal\E #more comment + /x + abc#not comment\n literal + +/abc#comment + \Q#not comment + literal\E #more comment/x + abc#not comment\n literal + +/\Qabc\$xyz\E/ + abc\\\$xyz + +/\Qabc\E\$\Qxyz\E/ + abc\$xyz + +/\Gabc/ + abc +\= Expect no match + xyzabc + +/\Gabc./g + abc1abc2xyzabc3 + +/abc./g + abc1abc2xyzabc3 + +/a(?x: b c )d/ + XabcdY +\= Expect no match + Xa b c d Y + +/((?x)x y z | a b c)/ + XabcY + AxyzB + +/(?i)AB(?-i)C/ + XabCY +\= Expect no match + XabcY + +/((?i)AB(?-i)C|D)E/ + abCE + DE +\= Expect no match + abcE + abCe + dE + De + +/(.*)\d+\1/ + abc123abc + abc123bc + +/(.*)\d+\1/s + abc123abc + abc123bc + +/((.*))\d+\1/ + abc123abc + abc123bc + +# This tests for an IPv6 address in the form where it can have up to +# eight components, one and only one of which is empty. This must be +# an internal component. + +/^(?!:) # colon disallowed at start + (?: # start of item + (?: [0-9a-f]{1,4} | # 1-4 hex digits or + (?(1)0 | () ) ) # if null previously matched, fail; else null + : # followed by colon + ){1,7} # end item; 1-7 of them required + [0-9a-f]{1,4} $ # final hex number at end of string + (?(1)|.) # check that there was an empty component + /ix + a123::a123 + a123:b342::abcd + a123:b342::324e:abcd + a123:ddde:b342::324e:abcd + a123:ddde:b342::324e:dcba:abcd + a123:ddde:9999:b342::324e:dcba:abcd +\= Expect no match + 1:2:3:4:5:6:7:8 + a123:bce:ddde:9999:b342::324e:dcba:abcd + a123::9999:b342::324e:dcba:abcd + abcde:2:3:4:5:6:7:8 + ::1 + abcd:fee0:123:: + :1 + 1: + +/[z\Qa-d]\E]/ + z + a + - + d + ] +\= Expect no match + b + +/(a+)*b/ +\= Expect no match + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/(?i)reg(?:ul(?:[a]|ae)r|ex)/ + REGular + regulaer + Regex + regulr + +/[--]+/ + + + + + +/(?<=Z)X./ + \x84XAZXB + +/ab cd (?x) de fg/ + ab cd defg + +/ab cd(?x) de fg/ + ab cddefg +\= Expect no match + abcddefg + +/(?a|)*\d/ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +\= Expect no match + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/(?:a|)*\d/ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4 +\= Expect no match + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/\Z/g + abc\n + +/^(?s)(?>.*)(?(a))b|(a)c/ + ac + +/(?=(a))ab|(a)c/ + ac + +/((?>(a))b|(a)c)/ + ac + +/((?>(a))b|(a)c)++/ + ac + +/(?:(?>(a))b|(a)c)++/ + ac + +/(?=(?>(a))b|(a)c)(..)/ + ac + +/(?>(?>(a))b|(a)c)/ + ac + +/(?:(?>([ab])))+a=/aftertext + =ba= + +/(?>([ab]))+a=/aftertext + =ba= + +/((?>(a+)b)+(aabab))/ + aaaabaaabaabab + +/(?>a+|ab)+?c/ +\= Expect no match + aabc + +/(?>a+|ab)+c/ +\= Expect no match + aabc + +/(?:a+|ab)+c/ + aabc + +/(?(?=(a))a)/ + a + +/(?(?=(a))a)(b)/ + ab + +/^(?:a|ab)++c/ +\= Expect no match + aaaabc + +/^(?>a|ab)++c/ +\= Expect no match + aaaabc + +/^(?:a|ab)+c/ + aaaabc + +/(?=abc){3}abc/aftertext + abcabcabc +\= Expect no match + xyz + +/(?=abc)+abc/aftertext + abcabcabc +\= Expect no match + xyz + +/(?=abc)++abc/aftertext + abcabcabc +\= Expect no match + xyz + +/(?=abc){0}xyz/ + xyz + +/(?=abc){1}xyz/ +\= Expect no match + xyz + +/(?=(a))?./ + ab + bc + +/(?=(a))??./ + ab + bc + +/^(?=(?1))?[az]([abc])d/ + abd + zcdxx + +/^(?!a){0}\w+/ + aaaaa + +/(?<=(abc))?xyz/ + abcxyz + pqrxyz + +/^[\g]+/ + ggg<<>> +\= Expect no match + \\ga + +/^[\ga]+/ + gggagagaxyz + +/^[:a[:digit:]]+/ + aaaa444:::Z + +/^[:a[:digit:]:b]+/ + aaaa444:::bbbZ + +/[:a]xxx[b:]/ + :xxx: + +/(?<=a{2})b/i + xaabc +\= Expect no match + xabc + +/(?XNNNYZ + > X NYQZ +\= Expect no match + >XYZ + > X NY Z + +/\v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c/ + >XY\x0aZ\x0aA\x0bNN\x0c + >\x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c + +/(foo)\Kbar/ + foobar + +/(foo)(\Kbar|baz)/ + foobar + foobaz + +/(foo\Kbar)baz/ + foobarbaz + +/abc\K|def\K/g,aftertext + Xabcdefghi + +/ab\Kc|de\Kf/g,aftertext + Xabcdefghi + +/(?=C)/g,aftertext + ABCDECBA + +/^abc\K/aftertext + abcdef +\= Expect no match + defabcxyz + +/^(a(b))\1\g1\g{1}\g-1\g{-1}\g{-2}Z/ + ababababbbabZXXXX + +/(?tom|bon)-\g{A}/ + tom-tom + bon-bon + +/(^(a|b\g{-1}))/ +\= Expect no match + bacxxx + +/(?|(abc)|(xyz))\1/ + abcabc + xyzxyz +\= Expect no match + abcxyz + xyzabc + +/(?|(abc)|(xyz))(?1)/ + abcabc + xyzabc +\= Expect no match + xyzxyz + +/^X(?5)(a)(?|(b)|(q))(c)(d)(Y)/ + XYabcdY + +/^X(?7)(a)(?|(b|(r)(s))|(q))(c)(d)(Y)/ + XYabcdY + +/^X(?7)(a)(?|(b|(?|(r)|(t))(s))|(q))(c)(d)(Y)/ + XYabcdY + +/(?'abc'\w+):\k{2}/ + a:aaxyz + ab:ababxyz +\= Expect no match + a:axyz + ab:abxyz + +/(?'abc'\w+):\g{abc}{2}/ + a:aaxyz + ab:ababxyz +\= Expect no match + a:axyz + ab:abxyz + +/^(?a)? (?()b|c) (?('ab')d|e)/x + abd + ce + +/^(a.)\g-1Z/ + aXaXZ + +/^(a.)\g{-1}Z/ + aXaXZ + +/^(?(DEFINE) (? a) (? b) ) (?&A) (?&B) /x + abcd + +/(?(?:(?:a(?&all))|(b))(c?))/ + aabc + +/(a(b)|(c))(?1)/ + abc + cab + +/(?1)(a(b)|(c))/ + abc + cab + +/(?(?&NAME_PAT))\s+(?(?&ADDRESS_PAT)) + (?(DEFINE) + (?[a-z]+) + (?\d+) + )/x + metcalfe 33 + +/(?(DEFINE)(?2[0-4]\d|25[0-5]|1\d\d|[1-9]?\d))\b(?&byte)(\.(?&byte)){3}/ + 1.2.3.4 + 131.111.10.206 + 10.0.0.0 +\= Expect no match + 10.6 + 455.3.4.5 + +/\b(?&byte)(\.(?&byte)){3}(?(DEFINE)(?2[0-4]\d|25[0-5]|1\d\d|[1-9]?\d))/ + 1.2.3.4 + 131.111.10.206 + 10.0.0.0 +\= Expect no match + 10.6 + 455.3.4.5 + +/^(\w++|\s++)*$/ + now is the time for all good men to come to the aid of the party +\= Expect no match + this is not a line with only words and spaces! + +/(\d++)(\w)/ + 12345a +\= Expect no match + 12345+ + +/a++b/ + aaab + +/(a++b)/ + aaab + +/(a++)b/ + aaab + +/([^()]++|\([^()]*\))+/ + ((abc(ade)ufh()()x + +/\(([^()]++|\([^()]+\))+\)/ + (abc) + (abc(def)xyz) +\= Expect no match + ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +/^([^()]|\((?1)*\))*$/ + abc + a(b)c + a(b(c))d +\= Expect no match) + a(b(c)d + +/^>abc>([^()]|\((?1)*\))*abc>123abc>1(2)3abc>(1(2)3)]*+) | (?2)) * >))/x + <> + + hij> + hij> + def> + +\= Expect no match + a)(?<=b(?&X))/ + baz + +/^(?|(abc)|(def))\1/ + abcabc + defdef +\= Expect no match + abcdef + defabc + +/^(?|(abc)|(def))(?1)/ + abcabc + defabc +\= Expect no match + defdef + abcdef + +/(?:a(? (?')|(?")) |b(? (?')|(?")) ) (?('quote')[a-z]+|[0-9]+)/x,dupnames + a\"aaaaa + b\"aaaaa +\= Expect no match + b\"11111 + +/(?:(?1)|B)(A(*F)|C)/ + ABCD + CCD +\= Expect no match + CAD + +/^(?:(?1)|B)(A(*F)|C)/ + CCD + BCD +\= Expect no match + ABCD + CAD + BAD + +/(?:(?1)|B)(A(*ACCEPT)XX|C)D/ + AAD + ACD + BAD + BCD + BAX +\= Expect no match + ACX + ABC + +/(?(DEFINE)(A))B(?1)C/ + BAC + +/(?(DEFINE)((A)\2))B(?1)C/ + BAAC + +/(? \( ( [^()]++ | (?&pn) )* \) )/x + (ab(cd)ef) + +/^(?=a(*SKIP)b|ac)/ +\= Expect no match + ac + +/^(?=a(*PRUNE)b)/ + ab +\= Expect no match + ac + +/^(?=a(*ACCEPT)b)/ + ac + +/(?>a\Kb)/ + ab + +/((?>a\Kb))/ + ab + +/(a\Kb)/ + ab + +/^a\Kcz|ac/ + ac + +/(?>a\Kbz|ab)/ + ab + +/^(?&t)(?(DEFINE)(?a\Kb))$/ + ab + +/^([^()]|\((?1)*\))*$/ + a(b)c + a(b(c)d)e + +/(?P(?P0)(?P>L1)|(?P>L2))/ + 0 + 00 + 0000 + +/(?P(?P0)|(?P>L2)(?P>L1))/ + 0 + 00 + 0000 + +# This one does fail, as expected, in Perl. It needs the complex item at the +# end of the pattern. A single letter instead of (B|D) makes it not fail, which +# I think is a Perl bug. + +/A(*COMMIT)(B|D)/ +\= Expect no match + ACABX + +# Check the use of names for failure + +/^(A(*PRUNE:A)B|C(*PRUNE:B)D)/mark +\= Expect no match + AC + CB + +/(*MARK:A)(*SKIP:B)(C|X)/mark + C +\= Expect no match + D + +/^(A(*THEN:A)B|C(*THEN:B)D)/mark +\= Expect no match + CB + +/^(?:A(*THEN:A)B|C(*THEN:B)D)/mark +\= Expect no match + CB + +/^(?>A(*THEN:A)B|C(*THEN:B)D)/mark +\= Expect no match + CB + +# This should succeed, as the skip causes bump to offset 1 (the mark). Note +# that we have to have something complicated such as (B|Z) at the end because, +# for Perl, a simple character somehow causes an unwanted optimization to mess +# with the handling of backtracking verbs. + +/A(*MARK:A)A+(*SKIP:A)(B|Z) | AC/x,mark + AAAC + +# Test skipping over a non-matching mark. + +/A(*MARK:A)A+(*MARK:B)(*SKIP:A)(B|Z) | AC/x,mark + AAAC + +# Check shorthand for MARK. + +/A(*:A)A+(*SKIP:A)(B|Z) | AC/x,mark + AAAC + +/(*:A)A+(*SKIP:A)(B|Z)/mark +\= Expect no match + AAAC + +# This should succeed, as a non-existent skip name disables the skip. + +/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC/x,mark + AAAC + +/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC(*:B)/x,mark + AAAC + +# COMMIT at the start of a pattern should act like an anchor. Again, however, +# we need the complication for Perl. + +/(*COMMIT)(A|P)(B|P)(C|P)/ + ABCDEFG +\= Expect no match + DEFGABC + +# COMMIT inside an atomic group can't stop backtracking over the group. + +/(\w+)(?>b(*COMMIT))\w{2}/ + abbb + +/(\w+)b(*COMMIT)\w{2}/ +\= Expect no match + abbb + +# Check opening parens in comment when seeking forward reference. + +/(?&t)(?#()(?(DEFINE)(?a))/ + bac + +# COMMIT should override THEN. + +/(?>(*COMMIT)(?>yes|no)(*THEN)(*F))?/ +\= Expect no match + yes + +/(?>(*COMMIT)(yes|no)(*THEN)(*F))?/ +\= Expect no match + yes + +/b?(*SKIP)c/ + bc + abc + +/(*SKIP)bc/ +\= Expect no match + a + +/(*SKIP)b/ +\= Expect no match + a + +/(?P(?P=abn)xxx|)+/ + xxx + +/(?i:([^b]))(?1)/ + aa + aA +\= Expect no match + ab + aB + Ba + ba + +/^(?&t)*+(?(DEFINE)(?a))\w$/ + aaaaaaX +\= Expect no match + aaaaaa + +/^(?&t)*(?(DEFINE)(?a))\w$/ + aaaaaaX + aaaaaa + +/^(a)*+(\w)/ + aaaaX + YZ +\= Expect no match + aaaa + +/^(?:a)*+(\w)/ + aaaaX + YZ +\= Expect no match + aaaa + +/^(a)++(\w)/ + aaaaX +\= Expect no match + aaaa + YZ + +/^(?:a)++(\w)/ + aaaaX +\= Expect no match + aaaa + YZ + +/^(a)?+(\w)/ + aaaaX + YZ + +/^(?:a)?+(\w)/ + aaaaX + YZ + +/^(a){2,}+(\w)/ + aaaaX +\= Expect no match + aaa + YZ + +/^(?:a){2,}+(\w)/ + aaaaX +\= Expect no match + aaa + YZ + +/(a|)*(?1)b/ + b + ab + aab + +/(a)++(?1)b/ +\= Expect no match + ab + aab + +/(a)*+(?1)b/ +\= Expect no match + ab + aab + +/(?1)(?:(b)){0}/ + b + +/(foo ( \( ((?:(?> [^()]+ )|(?2))*) \) ) )/x + foo(bar(baz)+baz(bop)) + +/(A (A|B(*ACCEPT)|C) D)(E)/x + AB + +/\A.*?(a|bc)/ + ba + +/\A.*?(?:a|bc)++/ + ba + +/\A.*?(a|bc)++/ + ba + +/\A.*?(?:a|bc|d)/ + ba + +/(?:(b))++/ + beetle + +/(?(?=(a(*ACCEPT)z))a)/ + a + +/^(a)(?1)+ab/ + aaaab + +/^(a)(?1)++ab/ +\= Expect no match + aaaab + +/^(?=a(*:M))aZ/mark + aZbc + +/^(?!(*:M)b)aZ/mark + aZbc + +/(?(DEFINE)(a))?b(?1)/ + backgammon + +/^\N+/ + abc\ndef + +/^\N{1,}/ + abc\ndef + +/(?(R)a+|(?R)b)/ + aaaabcde + +/(?(R)a+|((?R))b)/ + aaaabcde + +/((?(R)a+|(?1)b))/ + aaaabcde + +/((?(R1)a+|(?1)b))/ + aaaabcde + +/((?(R)a|(?1)))*/ + aaa + +/((?(R)a|(?1)))+/ + aaa + +/a(*:any +name)/mark + abc + +/(?>(?&t)c|(?&t))(?(DEFINE)(?a|b(*PRUNE)c))/ + a + ba + bba + +# Checking revised (*THEN) handling. + +# Capture + +/^.*? (a(*THEN)b) c/x +\= Expect no match + aabc + +/^.*? (a(*THEN)b|(*F)) c/x + aabc + +/^.*? ( (a(*THEN)b) | (*F) ) c/x + aabc + +/^.*? ( (a(*THEN)b) ) c/x +\= Expect no match + aabc + +# Non-capture + +/^.*? (?:a(*THEN)b) c/x +\= Expect no match + aabc + +/^.*? (?:a(*THEN)b|(*F)) c/x + aabc + +/^.*? (?: (?:a(*THEN)b) | (*F) ) c/x + aabc + +/^.*? (?: (?:a(*THEN)b) ) c/x +\= Expect no match + aabc + +# Atomic + +/^.*? (?>a(*THEN)b) c/x +\= Expect no match + aabc + +/^.*? (?>a(*THEN)b|(*F)) c/x + aabc + +/^.*? (?> (?>a(*THEN)b) | (*F) ) c/x + aabc + +/^.*? (?> (?>a(*THEN)b) ) c/x +\= Expect no match + aabc + +# Possessive capture + +/^.*? (a(*THEN)b)++ c/x +\= Expect no match + aabc + +/^.*? (a(*THEN)b|(*F))++ c/x + aabc + +/^.*? ( (a(*THEN)b)++ | (*F) )++ c/x + aabc + +/^.*? ( (a(*THEN)b)++ )++ c/x +\= Expect no match + aabc + +# Possessive non-capture + +/^.*? (?:a(*THEN)b)++ c/x +\= Expect no match + aabc + +/^.*? (?:a(*THEN)b|(*F))++ c/x + aabc + +/^.*? (?: (?:a(*THEN)b)++ | (*F) )++ c/x + aabc + +/^.*? (?: (?:a(*THEN)b)++ )++ c/x +\= Expect no match + aabc + +# Condition assertion + +/^(?(?=a(*THEN)b)ab|ac)/ + ac + +# Condition + +/^.*?(?(?=a)a|b(*THEN)c)/ +\= Expect no match + ba + +/^.*?(?:(?(?=a)a|b(*THEN)c)|d)/ + ba + +/^.*?(?(?=a)a(*THEN)b|c)/ +\= Expect no match + ac + +# Assertion + +/^.*(?=a(*THEN)b)/ + aabc + +# -------------------------- + +/(?>a(*:m))/imsx,mark + a + +/(?>(a)(*:m))/imsx,mark + a + +/(?<=a(*ACCEPT)b)c/ + xacd + +/(?<=(a(*COMMIT)b))c/ + xabcd +\= Expect no match + xacd + +/(?a?)*)*c/ + aac + +/(?>.*?a)(?<=ba)/ + aba + +/(?:.*?a)(?<=ba)/ + aba + +/(?>.*?a)b/s + aab + +/(?>.*?a)b/ + aab + +/(?>^a)b/s +\= Expect no match + aab + +/(?>.*?)(?<=(abcd)|(wxyz))/ + alphabetabcd + endingwxyz + +/(?>.*)(?<=(abcd)|(wxyz))/ + alphabetabcd + endingwxyz + +/(?>.*)foo/ +\= Expect no match + abcdfooxyz + +/(?>.*?)foo/ + abcdfooxyz + +/(?:(a(*PRUNE)b)){0}(?:(?1)|ac)/ + ac + +/(?:(a(*SKIP)b)){0}(?:(?1)|ac)/ + ac + +/(?<=(*SKIP)ac)a/ +\= Expect no match + aa + +/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC/x,mark + AAAC + +/a(*SKIP:m)x|ac(*:n)(*SKIP:n)d|ac/mark + acacd + +/A(*SKIP:m)x|A(*SKIP:n)x|AB/mark + AB + +/((*SKIP:r)d){0}a(*SKIP:m)x|ac(*:n)|ac/mark + acacd + +# Tests that try to figure out how Perl works. My hypothesis is that the first +# verb that is backtracked onto is the one that acts. This seems to be the case +# almost all the time, but there is one exception that is perhaps a bug. + +# This matches "aaaac"; each PRUNE advances one character until the subject no +# longer starts with 5 'a's. + +/aaaaa(*PRUNE)b|a+c/ + aaaaaac + +# Putting SKIP in front of PRUNE makes no difference, as it is never +# backtracked onto, whether or not it has a label. + +/aaaaa(*SKIP)(*PRUNE)b|a+c/ + aaaaaac + +/aaaaa(*SKIP:N)(*PRUNE)b|a+c/ + aaaaaac + +/aaaa(*:N)a(*SKIP:N)(*PRUNE)b|a+c/ + aaaaaac + +# Putting THEN in front makes no difference. + +/aaaaa(*THEN)(*PRUNE)b|a+c/ + aaaaaac + +# However, putting COMMIT in front of the prune changes it to "no match". I +# think this is inconsistent and possibly a bug. For the moment, running this +# test is moved out of the Perl-compatible file. + +/aaaaa(*COMMIT)(*PRUNE)b|a+c/ + +# OK, lets play the same game again using SKIP instead of PRUNE. + +# This matches "ac" because SKIP forces the next match to start on the +# sixth "a". + +/aaaaa(*SKIP)b|a+c/ + aaaaaac + +# Putting PRUNE in front makes no difference. + +/aaaaa(*PRUNE)(*SKIP)b|a+c/ + aaaaaac + +# Putting THEN in front makes no difference. + +/aaaaa(*THEN)(*SKIP)b|a+c/ + aaaaaac + +# In this case, neither does COMMIT. This still matches "ac". + +/aaaaa(*COMMIT)(*SKIP)b|a+c/ + aaaaaac + +# This gives "no match", as expected. + +/aaaaa(*COMMIT)b|a+c/ +\= Expect no match + aaaaaac + +# ---- Tests using THEN ---- + +# This matches "aaaaaac", as expected. + +/aaaaa(*THEN)b|a+c/ + aaaaaac + +# Putting SKIP in front makes no difference. + +/aaaaa(*SKIP)(*THEN)b|a+c/ + aaaaaac + +# Putting PRUNE in front makes no difference. + +/aaaaa(*PRUNE)(*THEN)b|a+c/ + aaaaaac + +# Putting COMMIT in front makes no difference. + +/aaaaa(*COMMIT)(*THEN)b|a+c/ + aaaaaac + +# End of "priority" tests + +/aaaaa(*:m)(*PRUNE:m)(*SKIP:m)m|a+/ + aaaaaa + +/aaaaa(*:m)(*MARK:m)(*PRUNE)(*SKIP:m)m|a+/ + aaaaaa + +/aaaaa(*:n)(*PRUNE:m)(*SKIP:m)m|a+/ + aaaaaa + +/aaaaa(*:n)(*MARK:m)(*PRUNE)(*SKIP:m)m|a+/ + aaaaaa + +/a(*MARK:A)aa(*PRUNE:A)a(*SKIP:A)b|a+c/ + aaaac + +/a(*MARK:A)aa(*MARK:A)a(*SKIP:A)b|a+c/ + aaaac + +/aaa(*PRUNE:A)a(*SKIP:A)b|a+c/ + aaaac + +/aaa(*MARK:A)a(*SKIP:A)b|a+c/ + aaaac + +/a(*:m)a(*COMMIT)(*SKIP:m)b|a+c/mark + aaaaaac + +/.?(a|b(*THEN)c)/ + ba + +/(a(*COMMIT)b)c|abd/ + abc +\= Expect no match + abd + +/(?=a(*COMMIT)b)abc|abd/ + abc + abd + +/(?>a(*COMMIT)b)c|abd/ + abc + abd + +/a(?=b(*COMMIT)c)[^d]|abd/ + abc +\= Expect no match + abd + +/a(?=bc).|abd/ + abd + abc + +/a(?>b(*COMMIT)c)d|abd/ +\= Expect no match + abceabd + +/a(?>bc)d|abd/ + abceabd + +/(?>a(*COMMIT)b)c|abd/ + abd + +/(?>a(*COMMIT)c)d|abd/ +\= Expect no match + abd + +/((?=a(*COMMIT)b)ab|ac){0}(?:(?1)|a(c))/ + ac + +# These tests were formerly in test 2, but changes in PCRE and Perl have +# made them compatible. + +/^(a)?(?(1)a|b)+$/ +\= Expect no match + a + +/A(*PRUNE:A)A+(*SKIP:A)(B|Z) | AC/x,mark +\= Expect no match + AAAC + +/^((abc|abcx)(*THEN)y|abcd)/ + abcd +\= Expect no match + abcxy + +/^((yes|no)(*THEN)(*F))?/ +\= Expect no match + yes + +/(A (.*) C? (*THEN) | A D) (*FAIL)/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) C? (*THEN) | A D) z/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) C? (*THEN) | A D) \s* (*FAIL)/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) C? (*THEN) | A D) \s* z/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) (?:C|) (*THEN) | A D) (*FAIL)/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) (?:C|) (*THEN) | A D) z/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) C{0,6} (*THEN) | A D) (*FAIL)/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) C{0,6} (*THEN) | A D) z/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) (CE){0,6} (*THEN) | A D) (*FAIL)/x +\= Expect no match + AbcdCEBefgBhiBqz + +/(A (.*) (CE){0,6} (*THEN) | A D) z/x +\= Expect no match + AbcdCEBefgBhiBqz + +/(A (.*) (CE*){0,6} (*THEN) | A D) (*FAIL)/x +\= Expect no match + AbcdCBefgBhiBqz + +/(A (.*) (CE*){0,6} (*THEN) | A D) z/x +\= Expect no match + AbcdCBefgBhiBqz + +/(?=a(*COMMIT)b|ac)ac|ac/ +\= Expect no match + ac + +/(?=a(*COMMIT)b|(ac)) ac | (a)c/x +\= Expect no match + ac + +# ---- + +/(?(?!b(*THEN)a)bn|bnn)/ + bnn + +/(?!b(*SKIP)a)bn|bnn/ + bnn + +/(?(?!b(*SKIP)a)bn|bnn)/ + bnn + +/(?!b(*PRUNE)a)bn|bnn/ + bnn + +/(?(?!b(*PRUNE)a)bn|bnn)/ + bnn + +/(?!b(*COMMIT)a)bn|bnn/ + bnn + +/(?(?!b(*COMMIT)a)bn|bnn)/ + bnn + +/(?=b(*SKIP)a)bn|bnn/ +\= Expect no match + bnn + +/(?=b(*THEN)a)bn|bnn/ + bnn + +/^(?!a(*SKIP)b)/ + ac + +/^(?!a(*SKIP)b)../ + acd + +/(?!a(*SKIP)b)../ + acd + +/^(?(?!a(*SKIP)b))/ + ac + +/^(?!a(*PRUNE)b)../ + acd + +/(?!a(*PRUNE)b)../ + acd + +/(?!a(*COMMIT)b)ac|cd/ + ac + +/\A.*?(?:a|bc)/ + ba + +/^(A(*THEN)B|C(*THEN)D)/ + CD + +/(*:m(m)(?&y)(?(DEFINE)(?b))/mark + abc + +/(*PRUNE:m(m)(?&y)(?(DEFINE)(?b))/mark + abc + +/(*SKIP:m(m)(?&y)(?(DEFINE)(?b))/mark + abc + +/(*THEN:m(m)(?&y)(?(DEFINE)(?b))/mark + abc + +/^\d*\w{4}/ + 1234 +\= Expect no match + 123 + +/^[^b]*\w{4}/ + aaaa +\= Expect no match + aaa + +/^[^b]*\w{4}/i + aaaa +\= Expect no match + aaa + +/^a*\w{4}/ + aaaa +\= Expect no match + aaa + +/^a*\w{4}/i + aaaa +\= Expect no match + aaa + +/(?:(?foo)|(?bar))\k/dupnames + foofoo + barbar + +/(?A)(?:(?foo)|(?bar))\k/dupnames + AfooA + AbarA +\= Expect no match + Afoofoo + Abarbar + +/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/ + 1 IN SOA non-sp1 non-sp2( + +/^ (?:(?A)|(?'B'B)(?A)) (?('A')x) (?()y)$/x,dupnames + Ax + BAxy + +/^A\xZ/ + A\0Z + +/^A\o{123}B/ + A\123B + +/ ^ a + + b $ /x + aaaab + +/ ^ a + #comment + + b $ /x + aaaab + +/ ^ a + #comment + #comment + + b $ /x + aaaab + +/ ^ (?> a + ) b $ /x + aaaab + +/ ^ ( a + ) + + \w $ /x + aaaab + +/(?:a\Kb)*+/aftertext + ababc + +/(?>a\Kb)*/aftertext + ababc + +/(?:a\Kb)*/aftertext + ababc + +/(a\Kb)*+/aftertext + ababc + +/(a\Kb)*/aftertext + ababc + +/(?:x|(?:(xx|yy)+|x|x|x|x|x)|a|a|a)bc/ +\= Expect no match + acb + +/\A(?:[^\"]++|\"(?:[^\"]*+|\"\")*+\")++/ + NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED + +/\A(?:[^\"]++|\"(?:[^\"]++|\"\")*+\")++/ + NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED + +/\A(?:[^\"]++|\"(?:[^\"]++|\"\")++\")++/ + NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED + +/\A([^\"1]++|[\"2]([^\"3]*+|[\"4][\"5])*+[\"6])++/ + NON QUOTED \"QUOT\"\"ED\" AFTER \"NOT MATCHED + +/^\w+(?>\s*)(?<=\w)/ + test test + +/(?Pa)(?Pb)/g,dupnames + abbaba + +/(?Pa)(?Pb)(?P=same)/g,dupnames + abbaba + +/(?P=same)?(?Pa)(?Pb)/g,dupnames + abbaba + +/(?:(?P=same)?(?:(?P=same)(?Pa)(?P=same)|(?P=same)?(?Pb)(?P=same)){2}(?P=same)(?Pc)(?P=same)){2}(?Pz)?/g,dupnames +\= Expect no match + bbbaaaccccaaabbbcc + +/(?Pa)?(?Pb)?(?()c|d)*l/ + acl + bdl + adl + bcl + +/\sabc/ + \x{0b}abc + +/[\Qa]\E]+/ + aa]] + +/[\Q]a\E]+/ + aa]] + +/A((((((((a))))))))\8B/ + AaaB + +/A(((((((((a)))))))))\9B/ + AaaB + +/A[\8\9]B/ + A8B + A9B + +/(|ab)*?d/ + abd + xyd + +/(?:((abcd))|(((?:(?:(?:(?:abc|(?:abcdef))))b)abcdefghi)abc)|((*ACCEPT)))/ + 1234abcd + +/(\2|a)(\1)/ + aaa + +/(\2)(\1)/ + +/Z*(|d*){216}/ + +/(?1)(?#?'){8}(a)/ + baaaaaaaaac + +/((((((((((((x))))))))))))\12/ + xx + +/A[\8]B[\9]C/ + A8B9C + +/(?1)()((((((\1++))\x85)+)|))/ + \x85\x85 + +/(?|(\k'Pm')|(?'Pm'))/ + abcd + +/(?|(aaa)|(b))\g{1}/ + aaaaaa + bb + +/(?|(aaa)|(b))(?1)/ + aaaaaa + baaa +\= Expect no match + bb + +/(?|(aaa)|(b))/ + xaaa + xbc + +/(?|(?'a'aaa)|(?'a'b))\k'a'/ + aaaaaa + bb + +/(?|(?'a'aaa)|(?'a'b))(?'a'cccc)\k'a'/dupnames + aaaccccaaa + bccccb + +# /x does not apply to MARK labels + +/x (*MARK:ab cd # comment +ef) x/x,mark + axxz + +/(?<=a(B){0}c)X/ + acX + +/(?b)(?(DEFINE)(a+))(?&DEFINE)/ + bbbb +\= Expect no match + baaab + +/(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[,;:])(?=.{8,16})(?!.*[\s])/ + \ Fred:099 + +/(?=.*X)X$/ + \ X + +/(?s)(?=.*?)b/ + aabc + +/(Z)(a)\2{1,2}?(?-i)\1X/i + ZaAAZX + +/(?'c')XX(?'YYYYYYYYYYYYYYYYYYYYYYYCl')/ + +/[s[:digit:]\E-H]+/ + s09-H + +/[s[:digit:]\Q\E-H]+/ + s09-H + +/a+(?:|b)a/ + aaaa + +/X?(R||){3335}/ + +/(?1)(A(*COMMIT)|B)D/ + ABD + XABD + BAD + ABXABD +\= Expect no match + ABX + +/(?(DEFINE)(? 1? (?=(?2)?) 1 2 (?('cond')|3))) + \A + () + (?&m) + \Z/x + 123 + +/^(?: +(?: A| (1? (?=(?2)?) (1) 2 (?('cond')|3)) ) +(Z) +)+$/x + AZ123Z +\= Expect no match + AZ12Z + +/^ (?(DEFINE) ( (?!(a)\2b)..) ) ()(?1) /x + acb +\= Expect no match + aab + +/(?>ab|abab){1,5}?M/ + abababababababababababM + +/(?>ab|abab){2}?M/ + abababM + +/((?(?=(a))a)+k)/ + bbak + +/((?(?=(a))a|)+k)/ + bbak + +/(?(?!(b))a|b)+k/ + ababbalbbadabak + +/(?!(b))c|b/ + Ab + Ac + +/(?=(b))b|c/ + Ab + Ac + +/^(.|(.)(?1)\2)$/ + a + aba + abcba + ababa + abcdcba + +/^((.)(?1)\2|.?)$/ + a + aba + abba + abcba + ababa + abccba + abcdcba + abcddcba + +/^(.)(\1|a(?2))/ + bab + +/^(.|(.)(?1)?\2)$/ + abcba + +/^(?(?=(a))abc|def)/ + abc + +/^(?(?!(a))def|abc)/ + abc + +/^(?(?=(a)(*ACCEPT))abc|def)/ + abc + +/^(?(?!(a)(*ACCEPT))def|abc)/ + abc + +/^(?1)\d{3}(a)/ + a123a + +/<(?x:[a b])>/xx + < > + +/<(?:[a b])>/xx + < > + +/<(?xxx:[a b])>/ + < > + +/<(?-x:[a b])>/xx + < > + +/[[:digit:]-]+/ + 12-24 + +/(?(DEFINE)(?a?)X)^(?&optional_a)a$/ + aa + a + +/^(a?)b(?1)a/ + abaa + aba + baa + ba + +/^(a?)+b(?1)a/ + abaa + aba + baa + ba + +/^(a?)++b(?1)a/ + abaa + aba + baa + ba + +/^(a?)+b/ + b + ab + aaab + +/(?=a+)a(a+)++b/ + aab + +/(?<=\G.)/g,aftertext + abc + +/(?<=(?=.)?)/ + +/(?<=(?=.)?+)/ + +/(?<=(?=.)*)/ + +/(?<=(?=.){4,5})/ + +/(?<=(?=.){4,5}x)/ + +/a(?=.(*:X))(*SKIP:X)(*F)|(.)/ + abc + +/a(?>(*:X))(*SKIP:X)(*F)|(.)/ + abc + +/a(?:(*:X))(*SKIP:X)(*F)|(.)/ + abc + +#pattern no_start_optimize + +/(?>a(*:1))(?>b(*:1))(*SKIP:1)x|.*/ + abc + +/(?>a(*:1))(?>b)(*SKIP:1)x|.*/ + abc + +#subject mark + +/a(*ACCEPT:X)b/ + abc + +/(?=a(*ACCEPT:QQ)bc)axyz/ + axyz + +/(?(DEFINE)(a(*ACCEPT:X)))(?1)b/ + abc + +/a(*F:X)b/ + abc + +/(?(DEFINE)(a(*F:X)))(?1)b/ + abc + +/a(*COMMIT:X)b/ + abc + +/(?(DEFINE)(a(*COMMIT:X)))(?1)b/ + abc + +/a+(*:Z)b(*COMMIT:X)(*SKIP:Z)c|.*/ + aaaabd + +/a+(*:Z)b(*COMMIT:X)(*SKIP:X)c|.*/ + aaaabd + +/a(*COMMIT:X)b/ + axabc + +#pattern -no_start_optimize +#subject -mark + +/(.COMMIT)(*COMMIT::::::::::interal error:::)/ + +/(*COMMIT:)/ + +/(*COMMIT:]w)/ + +/(?i)A(?^)B(?^x:C D)(?^i)e f/ + aBCDE F +\= Expect no match + aBCDEF + AbCDe f + +/(*pla:foo).{6}/ + abcfoobarxyz +\= Expect no match + abcfooba + +/(*positive_lookahead:foo).{6}/ + abcfoobarxyz + +/(?(*pla:foo).{6}|a..)/ + foobarbaz + abcfoobar + +/(?(*positive_lookahead:foo).{6}|a..)/ + foobarbaz + abcfoobar + +/(*plb:foo)bar/ + abcfoobar +\= Expect no match + abcbarfoo + +/(*positive_lookbehind:foo)bar/ + abcfoobar +\= Expect no match + abcbarfoo + +/(?(*plb:foo)bar|baz)/ + abcfoobar + bazfoobar + abcbazfoobar + foobazfoobar + +/(?(*positive_lookbehind:foo)bar|baz)/ + abcfoobar + bazfoobar + abcbazfoobar + foobazfoobar + +/(*nlb:foo)bar/ + abcbarfoo +\= Expect no match + abcfoobar + +/(*negative_lookbehind:foo)bar/ + abcbarfoo +\= Expect no match + abcfoobar + +/(?(*nlb:foo)bar|baz)/ + abcfoobaz + abcbarbaz +\= Expect no match + abcfoobar + +/(?(*negative_lookbehind:foo)bar|baz)/ + abcfoobaz + abcbarbaz +\= Expect no match + abcfoobar + +/(*atomic:a+)\w/ + aaab +\= Expect no match + aaaa + +/ (? \w+ )* \. /xi + pokus. + +/(?(DEFINE) (? \w+ ) ) (?&word)* \./xi + pokus. + +/(?(DEFINE) (? \w+ ) ) ( (?&word)* ) \./xi + pokus. + +/(?&word)* (?(DEFINE) (? \w+ ) ) \./xi + pokus. + +/(?&word)* \. (? \w+ )/xi + pokus.hokus + +/a(?(?=(*:2)b).)/mark + abc + acb + +/a(?(?!(*:2)b).)/mark + acb + abc + +/(?:a|ab){1}+c/ +\= Expect no match + abc + +/(a|ab){1}+c/ + abc + +/(a+){1}+a/ +\= Expect no match + aaaa + +/(?(DEFINE)(a|ab))(?1){1}+c/ + abc + +/(?:a|(?=b)|.)*\z/ + abc + +/(?:a|(?=b)|.)*/ + abc + +/(?<=a(*SKIP)x)|c/ + abcd + +/(?<=a(*SKIP)x)|d/ + abcd + +/(?<=(?=.(?<=x)))/aftertext + abx + +/(?<=(?=(?<=a)))b/ + ab + +/^(?a)(?()b)((?<=b).*)$/ + abc + +/^(a\1?){4}$/ + aaaa + aaaaaa + +/^((\1+)|\d)+133X$/ + 111133X + +/^(?>.*?([A-Z])(?!.*\1)){26}/i + The quick brown fox jumps over the lazy dog. + Jackdaws love my big sphinx of quartz. + Pack my box with five dozen liquor jugs. +\= Expect no match + The quick brown fox jumps over the lazy cat. + Hackdaws love my big sphinx of quartz. + Pack my fox with five dozen liquor jugs. + +/(?<=X(?(DEFINE)(A)))X(*F)/ +\= Expect no match + AXYZ + +/(?<=X(?(DEFINE)(A)))./ + AXYZ + +/(?<=X(?(DEFINE)(.*))Y)./ + AXYZ + +/(?<=X(?(DEFINE)(Y))(?1))./ + AXYZ + +/(?(DEFINE)(?bar))(?\x{8c}748364< + +/a{65536/ + >a{65536< + +/a\K.(?0)*/ + abac + +/(a\K.(?1)*)/ + abac + +# Altered interpretation of {,n} + +/a{,3}B/ + XBBB + XaBBB + XaaBBB + XaaaBBB + XaaaaBBB + +# But {,} remains not a qualifier + +/a{,}B/ + Xa{,}BBB +\= Expect no match + XBBB + XaBBB + +# Checks for non-quantifiers after refactored code + +/X{/ + ZZX{}YY + +/X{A/ + ZZX{ABC} + +/X{}/ + ZZX{}YZ + +/X{1234/ + ZZX{123456 + +/X{12ABC}/ + ZZX{12ABC}Y + +/X{1,/ + ZZX{1,... + +/X{,9/ + ZZX{,9}abc + +/X{,9]/ + ZZX{,9].. + +# -------------------------------------------------------------------------- + +/(A)(?-1)(?+1)(B)/ + xxAABBzz + +/(A)(\g{ -2 }B)/ + XAABX + +/(A)((?-2)B)/ + XAABX + +/a\c\X/ + --a\x1cX-- + +/(a)\g{ 1 }/ + baab + +/a{ 1,2 }/ + Xaaaaa + +/a{ 1 , 2 }/ + Xaaaaa + +/(?'name'ab)\k{ name }(?P=name)/ + XabababX + +/A{,}B/ + A{,}B + +/A{ , }B/ + A{ , }B + +/A{ ,3}/ + AAAAAACC + +/A{ 3, }/ + BBAAAAAACC + +# End of testinput1 diff --git a/testdata/pcre/testresult1.json b/testdata/pcre/testresult1.json new file mode 100644 index 0000000..afc7491 --- /dev/null +++ b/testdata/pcre/testresult1.json @@ -0,0 +1,22509 @@ +[ + { + "matchExpected": 1, + "pattern": "/the quick brown fox/", + "haystack": "the quick brown fox", + "match": [ + { + "match": "the quick brown fox" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/the quick brown fox/", + "haystack": "What do you know about the quick brown fox?", + "match": [ + { + "match": "the quick brown fox" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/the quick brown fox/", + "haystack": "The quick brown FOX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/the quick brown fox/", + "haystack": "What do you know about THE QUICK BROWN FOX?", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/The quick brown fox/i", + "haystack": "the quick brown fox", + "match": [ + { + "match": "the quick brown fox" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/The quick brown fox/i", + "haystack": "The quick brown FOX", + "match": [ + { + "match": "The quick brown FOX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/The quick brown fox/i", + "haystack": "What do you know about the quick brown fox?", + "match": [ + { + "match": "the quick brown fox" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/The quick brown fox/i", + "haystack": "What do you know about THE QUICK BROWN FOX?", + "match": [ + { + "match": "THE QUICK BROWN FOX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abcd\\t\\n\\r\\f\\a\\e\\071\\x3b\\$\\\\\\?caxyz/", + "haystack": "abcd\\t\\n\\r\\f\\a\\e9;\\$\\\\?caxyz", + "match": [ + { + "match": "abcd\\x09\\x0a\\x0d\\x0c\\x07\\x1b9;$\\?caxyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aabxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aabxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaabxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaaabxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abcxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abcxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aabcxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aabcxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqqqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqqqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqqqqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqqqqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqqqqqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqqqqqAzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypqqqqqqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaaabcxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abxyzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aabxyzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aabxyzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabxyzzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaabxyzzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabxyzzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaaabxyzzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abcxyzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abcxyzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aabcxyzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aabcxyzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaabcxyzzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzzzzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaaabcxyzzzzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzzzzpqrrrabbbxyyyypqAzz", + "match": [ + { + "match": "aaaabcxyzzzzpqrrrabbbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz", + "match": [ + { + "match": "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypABzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypABzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypABBzz", + "match": [ + { + "match": "aaabcxyzpqrrrabbxyyyypABBzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": ">>>aaabxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaabxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": ">aaaabxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "aaaabxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": ">>>>abcxyzpqrrrabbxyyyypqAzz", + "match": [ + { + "match": "abcxyzpqrrrabbxyyyypqAzz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzpqrrabbxyyyypqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzpqrrrrabbxyyyypqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "abxyzpqrrrabxyyyypqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaaabcxyzzzzpqrrrabbbxyyypqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/", + "haystack": "aaabcxyzpqrrrabbxyyyypqqqqqqqAzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(abc){1,2}zz/", + "haystack": "abczz", + "match": [ + { + "match": "abczz", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(abc){1,2}zz/", + "haystack": "abcabczz", + "match": [ + { + "match": "abcabczz", + "group1": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(abc){1,2}zz/", + "haystack": "zz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(abc){1,2}zz/", + "haystack": "abcabcabczz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(abc){1,2}zz/", + "haystack": ">>abczz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bc", + "match": [ + { + "match": "bc", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbc", + "match": [ + { + "match": "bbc", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbbc", + "match": [ + { + "match": "bbbc", + "group1": "bb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bac", + "match": [ + { + "match": "bac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbac", + "match": [ + { + "match": "bbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "aac", + "match": [ + { + "match": "aac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "abbbbbbbbbbbc", + "match": [ + { + "match": "abbbbbbbbbbbc", + "group1": "bbbbbbbbbbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbbbbbbbbbbac", + "match": [ + { + "match": "bbbbbbbbbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "aaac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "abbbbbbbbbbbac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bc", + "match": [ + { + "match": "bc", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bbc", + "match": [ + { + "match": "bbc", + "group1": "bb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bbbc", + "match": [ + { + "match": "bbbc", + "group1": "bbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bac", + "match": [ + { + "match": "bac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bbac", + "match": [ + { + "match": "bbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "aac", + "match": [ + { + "match": "aac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "abbbbbbbbbbbc", + "match": [ + { + "match": "abbbbbbbbbbbc", + "group1": "bbbbbbbbbbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "bbbbbbbbbbbac", + "match": [ + { + "match": "bbbbbbbbbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "aaac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}c/", + "haystack": "abbbbbbbbbbbac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(ba|b*){1,2}?bc/", + "haystack": "babc", + "match": [ + { + "match": "babc", + "group1": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ba|b*){1,2}?bc/", + "haystack": "bbabc", + "match": [ + { + "match": "bbabc", + "group1": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ba|b*){1,2}?bc/", + "haystack": "bababc", + "match": [ + { + "match": "bababc", + "group1": "ba" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(ba|b*){1,2}?bc/", + "haystack": "bababbc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(ba|b*){1,2}?bc/", + "haystack": "babababc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\ca\\cA\\c[;\\c:/", + "haystack": "\\x01\\x01\\e;z", + "match": [ + { + "match": "\\x01\\x01\\x1b;z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "athing", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "bthing", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "]thing", + "match": [ + { + "match": "]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "cthing", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "dthing", + "match": [ + { + "match": "d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "ething", + "match": [ + { + "match": "e" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[ab\\]cde]/", + "haystack": "fthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "[thing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[ab\\]cde]/", + "haystack": "\\\\thing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[]cde]/", + "haystack": "]thing", + "match": [ + { + "match": "]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[]cde]/", + "haystack": "cthing", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[]cde]/", + "haystack": "dthing", + "match": [ + { + "match": "d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[]cde]/", + "haystack": "ething", + "match": [ + { + "match": "e" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[]cde]/", + "haystack": "athing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[]cde]/", + "haystack": "fthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "fthing", + "match": [ + { + "match": "f" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "[thing", + "match": [ + { + "match": "[" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "\\\\thing", + "match": [ + { + "match": "\\" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[^ab\\]cde]/", + "haystack": "athing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "bthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "]thing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "cthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "dthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^ab\\]cde]/", + "haystack": "ething", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^]cde]/", + "haystack": "athing", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[^]cde]/", + "haystack": "fthing", + "match": [ + { + "match": "f" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[^]cde]/", + "haystack": "]thing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^]cde]/", + "haystack": "cthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^]cde]/", + "haystack": "dthing", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^]cde]/", + "haystack": "ething", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\/", + "haystack": "", + "match": [ + { + "match": "\\x81" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^ÿ/", + "haystack": "ÿ", + "match": [ + { + "match": "\\xff" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "0", + "match": [ + { + "match": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "1", + "match": [ + { + "match": "1" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "2", + "match": [ + { + "match": "2" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "3", + "match": [ + { + "match": "3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "4", + "match": [ + { + "match": "4" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "5", + "match": [ + { + "match": "5" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "6", + "match": [ + { + "match": "6" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "7", + "match": [ + { + "match": "7" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "8", + "match": [ + { + "match": "8" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "9", + "match": [ + { + "match": "9" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "10", + "match": [ + { + "match": "10" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9]+$/", + "haystack": "100", + "match": [ + { + "match": "100" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[0-9]+$/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*nter/", + "haystack": "enter", + "match": [ + { + "match": "enter" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*nter/", + "haystack": "inter", + "match": [ + { + "match": "inter" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*nter/", + "haystack": "uponter", + "match": [ + { + "match": "uponter" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^xxx[0-9]+$/", + "haystack": "xxx0", + "match": [ + { + "match": "xxx0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^xxx[0-9]+$/", + "haystack": "xxx1234", + "match": [ + { + "match": "xxx1234" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^xxx[0-9]+$/", + "haystack": "xxx", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.+[0-9][0-9][0-9]$/", + "haystack": "x123", + "match": [ + { + "match": "x123" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+[0-9][0-9][0-9]$/", + "haystack": "x1234", + "match": [ + { + "match": "x1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+[0-9][0-9][0-9]$/", + "haystack": "xx123", + "match": [ + { + "match": "xx123" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+[0-9][0-9][0-9]$/", + "haystack": "123456", + "match": [ + { + "match": "123456" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.+[0-9][0-9][0-9]$/", + "haystack": "123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.+?[0-9][0-9][0-9]$/", + "haystack": "x123", + "match": [ + { + "match": "x123" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+?[0-9][0-9][0-9]$/", + "haystack": "x1234", + "match": [ + { + "match": "x1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+?[0-9][0-9][0-9]$/", + "haystack": "xx123", + "match": [ + { + "match": "xx123" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.+?[0-9][0-9][0-9]$/", + "haystack": "123456", + "match": [ + { + "match": "123456" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.+?[0-9][0-9][0-9]$/", + "haystack": "123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$/", + "haystack": "abc!pqr=apquxz.ixr.zzz.ac.uk", + "match": [ + { + "match": "abc!pqr=apquxz.ixr.zzz.ac.uk", + "group1": "abc", + "group2": "pqr" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$/", + "haystack": "!pqr=apquxz.ixr.zzz.ac.uk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$/", + "haystack": "abc!=apquxz.ixr.zzz.ac.uk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$/", + "haystack": "abc!pqr=apquxz:ixr.zzz.ac.uk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^!]+)!(.+)=apquxz\\.ixr\\.zzz\\.ac\\.uk$/", + "haystack": "abc!pqr=apquxz.ixr.zzz.ac.ukk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/:/", + "haystack": "Well, we need a colon: somewhere", + "match": [ + { + "match": ":" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/:/", + "haystack": "Fail without a colon", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "0abc", + "match": [ + { + "match": "0abc", + "group1": "0abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "fed", + "match": [ + { + "match": "fed", + "group1": "fed" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "E", + "match": [ + { + "match": "E", + "group1": "E" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "::", + "match": [ + { + "match": "::", + "group1": "::" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "5f03:12C0::932e", + "match": [ + { + "match": "5f03:12C0::932e", + "group1": "5f03:12C0::932e" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "fed def", + "match": [ + { + "match": "def", + "group1": "def" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "Any old stuff", + "match": [ + { + "match": "ff", + "group1": "ff" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "0zzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "gzzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "fed\\x20", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/([\\da-f:]+)$/i", + "haystack": "Any old rubbish", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", + "haystack": ".1.2.3", + "match": [ + { + "match": ".1.2.3", + "group1": "1", + "group2": "2", + "group3": "3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", + "haystack": "A.12.123.0", + "match": [ + { + "match": "A.12.123.0", + "group1": "12", + "group2": "123", + "group3": "0" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", + "haystack": ".1.2.3333", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", + "haystack": "1.2.3", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/", + "haystack": "1234.2.3", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$/", + "haystack": "1 IN SOA non-sp1 non-sp2(", + "match": [ + { + "match": "1 IN SOA non-sp1 non-sp2(", + "group1": "1", + "group2": "non-sp1", + "group3": "non-sp2" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$/", + "haystack": "1 IN SOA non-sp1 non-sp2 (", + "match": [ + { + "match": "1 IN SOA non-sp1 non-sp2 (", + "group1": "1", + "group2": "non-sp1", + "group3": "non-sp2" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$/", + "haystack": "1IN SOA non-sp1 non-sp2(", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "a.", + "match": [ + { + "match": "a." + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "Z.", + "match": [ + { + "match": "Z." + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "2.", + "match": [ + { + "match": "2." + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "ab-c.pq-r.", + "match": [ + { + "match": "ab-c.pq-r.", + "group1": ".pq-r" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "sxk.zzz.ac.uk.", + "match": [ + { + "match": "sxk.zzz.ac.uk.", + "group1": ".uk" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "x-.y-.", + "match": [ + { + "match": "x-.y-.", + "group1": ".y-" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[a-zA-Z\\d][a-zA-Z\\d\\-]*(\\.[a-zA-Z\\d][a-zA-z\\d\\-]*)*\\.$/", + "haystack": "-abc.peq.", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.a", + "match": [ + { + "match": "*.a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.b0-a", + "match": [ + { + "match": "*.b0-a", + "group1": "0-a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.c3-b.c", + "match": [ + { + "match": "*.c3-b.c", + "group1": "3-b", + "group2": ".c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.c-a.b-c", + "match": [ + { + "match": "*.c-a.b-c", + "group1": "-a", + "group2": ".b-c", + "group3": "-c" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.0", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.a-", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.a-b.c-", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\*\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?(\\.[a-z]([a-z\\-\\d]*[a-z\\d]+)?)*$/", + "haystack": "*.c-a.0-c", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?=ab(de))(abd)(e)/", + "haystack": "abde", + "match": [ + { + "match": "abde", + "group1": "de", + "group2": "abd", + "group3": "e" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!(ab)de|x)(abd)(f)/", + "haystack": "abdf", + "match": [ + { + "match": "abdf", + "group2": "abd", + "group3": "f" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?=(ab(cd)))(ab)/", + "haystack": "abcd", + "match": [ + { + "match": "ab", + "group1": "abcd", + "group2": "cd", + "group3": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\da-f](\\.[\\da-f])*$/i", + "haystack": "a.b.c.d", + "match": [ + { + "match": "a.b.c.d", + "group1": ".d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\da-f](\\.[\\da-f])*$/i", + "haystack": "A.B.C.D", + "match": [ + { + "match": "A.B.C.D", + "group1": ".D" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\da-f](\\.[\\da-f])*$/i", + "haystack": "a.b.c.1.2.3.C", + "match": [ + { + "match": "a.b.c.1.2.3.C", + "group1": ".C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\\".*\\\"\\s*(;.*)?$/", + "haystack": "\\\"1234\\\"", + "match": [ + { + "match": "\"1234\"" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\\".*\\\"\\s*(;.*)?$/", + "haystack": "\\\"abcd\\\" ;", + "match": [ + { + "match": "\"abcd\" ;", + "group1": ";" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\\".*\\\"\\s*(;.*)?$/", + "haystack": "\\\"\\\" ; rhubarb", + "match": [ + { + "match": "\"\" ; rhubarb", + "group1": "; rhubarb" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\\".*\\\"\\s*(;.*)?$/", + "haystack": "\\\"1234\\\" : things", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^$/", + "haystack": "\\", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^$/", + "haystack": "A non-empty line", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/x", + "haystack": "ab c", + "match": [ + { + "match": "ab c" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/x", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/x", + "haystack": "ab cde", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/", + "haystack": "ab c", + "match": [ + { + "match": "ab c" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?x) ^ a (?# begins with a) b\\sc (?# then b c) $ (?# then end)/", + "haystack": "ab cde", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^ a\\ b[c ]d $/x", + "haystack": "a bcd", + "match": [ + { + "match": "a bcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^ a\\ b[c ]d $/x", + "haystack": "a b d", + "match": [ + { + "match": "a b d" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^ a\\ b[c ]d $/x", + "haystack": "abcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^ a\\ b[c ]d $/x", + "haystack": "ab d", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/", + "haystack": "abcdefhijklm", + "match": [ + { + "match": "abcdefhijklm", + "group1": "abc", + "group2": "bc", + "group3": "c", + "group4": "def", + "group5": "ef", + "group6": "f", + "group7": "hij", + "group8": "ij", + "group9": "j", + "group10": "klm", + "group11": "lm", + "group12": "m" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/", + "haystack": "abcdefhijklm", + "match": [ + { + "match": "abcdefhijklm", + "group1": "bc", + "group2": "c", + "group3": "ef", + "group4": "f", + "group5": "ij", + "group6": "j", + "group7": "lm", + "group8": "m" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\w][\\W][\\s][\\S][\\d][\\D][\\b][\\n][\\c]][\\022]/", + "haystack": "a+ Z0+\\x08\\n\\x1d\\x12", + "match": [ + { + "match": "a+ Z0+\\x08\\x0a\\x1d\\x12" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[.^$|()*+?{,}]+/", + "haystack": ".^\\$(*+)|{?,?}", + "match": [ + { + "match": ".^$(*+)|{?,?}" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "z", + "match": [ + { + "match": "z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "az", + "match": [ + { + "match": "az" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "aaaz", + "match": [ + { + "match": "aaaz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "aa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "a+", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w/", + "haystack": "aa+", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "z", + "match": [ + { + "match": "z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "az", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "aaaz", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "aa", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "aaaa", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "a+", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a*?\\w/", + "haystack": "aa+", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+\\w/", + "haystack": "az", + "match": [ + { + "match": "az" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+\\w/", + "haystack": "aaaz", + "match": [ + { + "match": "aaaz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+\\w/", + "haystack": "aa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+\\w/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+\\w/", + "haystack": "aa+", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+?\\w/", + "haystack": "az", + "match": [ + { + "match": "az" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+?\\w/", + "haystack": "aaaz", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+?\\w/", + "haystack": "aa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+?\\w/", + "haystack": "aaaa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a+?\\w/", + "haystack": "aa+", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8}\\w{2,}/", + "haystack": "1234567890", + "match": [ + { + "match": "1234567890" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8}\\w{2,}/", + "haystack": "12345678ab", + "match": [ + { + "match": "12345678ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8}\\w{2,}/", + "haystack": "12345678__", + "match": [ + { + "match": "12345678__" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\d{8}\\w{2,}/", + "haystack": "1234567", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}$/", + "haystack": "uoie", + "match": [ + { + "match": "uoie" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}$/", + "haystack": "1234", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}$/", + "haystack": "12345", + "match": [ + { + "match": "12345" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}$/", + "haystack": "aaaaa", + "match": [ + { + "match": "aaaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[aeiou\\d]{4,5}$/", + "haystack": "123456", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}?/", + "haystack": "uoie", + "match": [ + { + "match": "uoie" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}?/", + "haystack": "1234", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}?/", + "haystack": "12345", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}?/", + "haystack": "aaaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[aeiou\\d]{4,5}?/", + "haystack": "123456", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A(abc|def)=(\\1){2,3}\\Z/", + "haystack": "abc=abcabc", + "match": [ + { + "match": "abc=abcabc", + "group1": "abc", + "group2": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A(abc|def)=(\\1){2,3}\\Z/", + "haystack": "def=defdefdef", + "match": [ + { + "match": "def=defdefdef", + "group1": "def", + "group2": "def" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\A(abc|def)=(\\1){2,3}\\Z/", + "haystack": "abc=defdef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$/", + "haystack": "abcdefghijkcda2", + "match": [ + { + "match": "abcdefghijkcda2", + "group1": "a", + "group2": "b", + "group3": "c", + "group4": "d", + "group5": "e", + "group6": "f", + "group7": "g", + "group8": "h", + "group9": "i", + "group10": "j", + "group11": "k", + "group12": "cd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11*(\\3\\4)\\1(?#)2$/", + "haystack": "abcdefghijkkkkcda2", + "match": [ + { + "match": "abcdefghijkkkkcda2", + "group1": "a", + "group2": "b", + "group3": "c", + "group4": "d", + "group5": "e", + "group6": "f", + "group7": "g", + "group8": "h", + "group9": "i", + "group10": "j", + "group11": "k", + "group12": "cd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(cat(a(ract|tonic)|erpillar)) \\1()2(3)/", + "haystack": "cataract cataract23", + "match": [ + { + "match": "cataract cataract23", + "group1": "cataract", + "group2": "aract", + "group3": "ract", + "group4": "", + "group5": "3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(cat(a(ract|tonic)|erpillar)) \\1()2(3)/", + "haystack": "catatonic catatonic23", + "match": [ + { + "match": "catatonic catatonic23", + "group1": "catatonic", + "group2": "atonic", + "group3": "tonic", + "group4": "", + "group5": "3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(cat(a(ract|tonic)|erpillar)) \\1()2(3)/", + "haystack": "caterpillar caterpillar23", + "match": [ + { + "match": "caterpillar caterpillar23", + "group1": "caterpillar", + "group2": "erpillar", + "group4": "", + "group5": "3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/", + "haystack": "From abcd Mon Sep 01 12:33:02 1997", + "match": [ + { + "match": "From abcd Mon Sep 01 12:33", + "group1": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d/", + "haystack": "From abcd Mon Sep 01 12:33:02 1997", + "match": [ + { + "match": "From abcd Mon Sep 01 12:33", + "group1": "Sep " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d/", + "haystack": "From abcd Mon Sep 1 12:33:02 1997", + "match": [ + { + "match": "From abcd Mon Sep 1 12:33", + "group1": "Sep " + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^From\\s+\\S+\\s+([a-zA-Z]{3}\\s+){2}\\d{1,2}\\s+\\d\\d:\\d\\d/", + "haystack": "From abcd Sep 01 12:33:02 1997", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^12.34/s", + "haystack": "12\\n34", + "match": [ + { + "match": "12\\x0a34" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^12.34/s", + "haystack": "12\\r34", + "match": [ + { + "match": "12\\x0d34" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\w+(?=\\t)/", + "haystack": "the quick brown\\t fox", + "match": [ + { + "match": "brown" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/foo(?!bar)(.*)/", + "haystack": "foobar is foolish see?", + "match": [ + { + "match": "foolish see?", + "group1": "lish see?" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?!foo)...|^.{0,2})bar(.*)/", + "haystack": "foobar crowbar etc", + "match": [ + { + "match": "rowbar etc", + "group1": " etc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?!foo)...|^.{0,2})bar(.*)/", + "haystack": "barrel", + "match": [ + { + "match": "barrel", + "group1": "rel" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?!foo)...|^.{0,2})bar(.*)/", + "haystack": "2barrel", + "match": [ + { + "match": "2barrel", + "group1": "rel" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?!foo)...|^.{0,2})bar(.*)/", + "haystack": "A barrel", + "match": [ + { + "match": "A barrel", + "group1": "rel" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(\\D*)(?=\\d)(?!123)/", + "haystack": "abc456", + "match": [ + { + "match": "abc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(\\D*)(?=\\d)(?!123)/", + "haystack": "abc123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^1234(?# test newlines\n inside)/", + "haystack": "1234", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^1234 #comment in extended re\n /x", + "haystack": "1234", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/#rhubarb\n abcd/x", + "haystack": "abcd", + "match": [ + { + "match": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abcd#rhubarb/x", + "haystack": "abcd", + "match": [ + { + "match": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)\\1{2,3}(.)/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)\\1{2,3}(.)/", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)\\1{2,3}(.)/", + "haystack": "aaaaab", + "match": [ + { + "match": "aaaaa", + "group1": "a", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)\\1{2,3}(.)/", + "haystack": "aaaaaab", + "match": [ + { + "match": "aaaaa", + "group1": "a", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!^)abc/", + "haystack": "the abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?!^)abc/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=^)abc/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=^)abc/", + "haystack": "the abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[ab]{1,3}(ab*|b)/", + "haystack": "aabbbbb", + "match": [ + { + "match": "aabb", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab]{1,3}?(ab*|b)/", + "haystack": "aabbbbb", + "match": [ + { + "match": "aabbbbb", + "group1": "abbbbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab]{1,3}?(ab*?|b)/", + "haystack": "aabbbbb", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[ab]{1,3}(ab*?|b)/", + "haystack": "aabbbbb", + "match": [ + { + "match": "aabb", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "Alan Other ", + "match": [ + { + "match": "Alan Other " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "", + "match": [ + { + "match": "user@dom.ain" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "user\\@dom.ain", + "match": [ + { + "match": "user@dom.ain" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "\\\"A. Other\\\" (a comment)", + "match": [ + { + "match": "\"A. Other\" (a comment)" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "A. Other (a comment)", + "match": [ + { + "match": " Other (a comment)" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "\\\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\\\"\\@x400-re.lay", + "match": [ + { + "match": "\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"@x400-re.lay" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional leading comment\n(?: (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "A missing angle @,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # one word, optionally followed by....\n(?:\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] | # atom and space parts, or...\n\\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) | # comments, or...\n\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n# quoted strings\n)*\n< (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # leading <\n(?: @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* , (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n)* # further okay, if led by comma\n: # closing colon\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* )? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) # initial word\n(?: (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\" (?: # opening quote...\n[^\\\\\\x80-\\xff\\n\\015\"] # Anything except backslash and quote\n| # or\n\\\\ [^\\x80-\\xff] # Escaped something (something != CR)\n)* \" # closing quote\n) )* # further okay, if led by a period\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* @ (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # initial subdomain\n(?: #\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* \\. # if led by a period...\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* (?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n| \\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n) # ...further okay\n)*\n# address spec\n(?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* > # trailing >\n# name and address\n) (?: [\\040\\t] | \\(\n(?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] | \\( (?: [^\\\\\\x80-\\xff\\n\\015()] | \\\\ [^\\x80-\\xff] )* \\) )*\n\\) )* # optional trailing comment\n/x", + "haystack": "The quick brown fox", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "Alan Other ", + "match": [ + { + "match": "Alan Other " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "", + "match": [ + { + "match": "user@dom.ain" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "user\\@dom.ain", + "match": [ + { + "match": "user@dom.ain" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "\\\"A. Other\\\" (a comment)", + "match": [ + { + "match": "\"A. Other\" " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "A. Other (a comment)", + "match": [ + { + "match": " Other " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "\\\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\\\"\\@x400-re.lay", + "match": [ + { + "match": "\"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"@x400-re.lay" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional leading comment\n(?:\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "A missing angle @,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address\n| # or\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n# leading word\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # \"normal\" atoms and or spaces\n(?:\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n|\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n) # \"special\" comment or quoted string\n[^()<>@,;:\".\\\\\\[\\]\\x80-\\xff\\000-\\010\\012-\\037] * # more \"normal\"\n)*\n<\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# <\n(?:\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n(?: ,\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n)* # additional domains\n:\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)? # optional route\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n# Atom\n| # or\n\" # \"\n[^\\\\\\x80-\\xff\\n\\015\"] * # normal\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015\"] * )* # ( special normal* )*\n\" # \"\n# Quoted string\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# additional words\n)*\n@\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n(?:\n\\.\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n(?:\n[^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]+ # some number of atom characters...\n(?![^(\\040)<>@,;:\".\\\\\\[\\]\\000-\\037\\x80-\\xff]) # ..not followed by something that could be part of an atom\n|\n\\[ # [\n(?: [^\\\\\\x80-\\xff\\n\\015\\[\\]] | \\\\ [^\\x80-\\xff] )* # stuff\n\\] # ]\n)\n[\\040\\t]* # Nab whitespace.\n(?:\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: # (\n(?: \\\\ [^\\x80-\\xff] |\n\\( # (\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n(?: \\\\ [^\\x80-\\xff] [^\\\\\\x80-\\xff\\n\\015()] * )* # (special normal*)*\n\\) # )\n) # special\n[^\\\\\\x80-\\xff\\n\\015()] * # normal*\n)* # )*\n\\) # )\n[\\040\\t]* )* # If comment found, allow more spaces.\n# optional trailing comments\n)*\n# address spec\n> # >\n# name and address\n)\n/x", + "haystack": "The quick brown fox", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/abc\\0def\\00pqr\\000xyz\\0000AB/", + "haystack": "abc\\0def\\00pqr\\000xyz\\0000AB", + "match": [ + { + "match": "abc\\x00def\\x00pqr\\x00xyz\\x000AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc\\0def\\00pqr\\000xyz\\0000AB/", + "haystack": "abc456 abc\\0def\\00pqr\\000xyz\\0000ABCDE", + "match": [ + { + "match": "abc\\x00def\\x00pqr\\x00xyz\\x000AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc\\x0def\\x00pqr\\x000xyz\\x0000AB/", + "haystack": "abc\\x0def\\x00pqr\\x000xyz\\x0000AB", + "match": [ + { + "match": "abc\\x0def\\x00pqr\\x000xyz\\x0000AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc\\x0def\\x00pqr\\x000xyz\\x0000AB/", + "haystack": "abc456 abc\\x0def\\x00pqr\\x000xyz\\x0000ABCDE", + "match": [ + { + "match": "abc\\x0def\\x00pqr\\x000xyz\\x0000AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\000-\\037]/", + "haystack": "\\0A", + "match": [ + { + "match": "\\x00" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\000-\\037]/", + "haystack": "\\01B", + "match": [ + { + "match": "\\x01" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\000-\\037]/", + "haystack": "\\037C", + "match": [ + { + "match": "\\x1f" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\0*/", + "haystack": "\\0\\0\\0\\0", + "match": [ + { + "match": "\\x00\\x00\\x00\\x00" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A\\x0{2,3}Z/", + "haystack": "The A\\x0\\x0Z", + "match": [ + { + "match": "A\\x00\\x00Z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A\\x0{2,3}Z/", + "haystack": "An A\\0\\x0\\0Z", + "match": [ + { + "match": "A\\x00\\x00\\x00Z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/A\\x0{2,3}Z/", + "haystack": "A\\0Z", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/A\\x0{2,3}Z/", + "haystack": "A\\0\\x0\\0\\x0Z", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(cow|)\\1(bell)/", + "haystack": "cowcowbell", + "match": [ + { + "match": "cowcowbell", + "group1": "cow", + "group2": "bell" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(cow|)\\1(bell)/", + "haystack": "bell", + "match": [ + { + "match": "bell", + "group1": "", + "group2": "bell" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(cow|)\\1(bell)/", + "haystack": "cowbell", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\s/", + "haystack": "\\040abc", + "match": [ + { + "match": " " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\s/", + "haystack": "\\x0cabc", + "match": [ + { + "match": "\\x0c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\s/", + "haystack": "\\nabc", + "match": [ + { + "match": "\\x0a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\s/", + "haystack": "\\rabc", + "match": [ + { + "match": "\\x0d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\s/", + "haystack": "\\tabc", + "match": [ + { + "match": "\\x09" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\s/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^a\tb\n \f c/x", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1*b/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1*b/", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1*b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a|)\\1*b/", + "haystack": "acb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1+b/", + "haystack": "aab", + "match": [ + { + "match": "aab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1+b/", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1+b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a|)\\1+b/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1?b/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1?b/", + "haystack": "aab", + "match": [ + { + "match": "aab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1?b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a|)\\1?b/", + "haystack": "acb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2}b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2}b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a|)\\1{2}b/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2}b/", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2}b/", + "haystack": "aaaab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a|)\\1{2,3}b/", + "haystack": "aaaaab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ab{1,3}bc/", + "haystack": "abbbbc", + "match": [ + { + "match": "abbbbc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ab{1,3}bc/", + "haystack": "abbbc", + "match": [ + { + "match": "abbbc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ab{1,3}bc/", + "haystack": "abbc", + "match": [ + { + "match": "abbc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ab{1,3}bc/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ab{1,3}bc/", + "haystack": "abbbbbc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/([^.]*)\\.([^:]*):[T ]+(.*)/", + "haystack": "track1.title:TBlah blah blah", + "match": [ + { + "match": "track1.title:TBlah blah blah", + "group1": "track1", + "group2": "title", + "group3": "Blah blah blah" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^.]*)\\.([^:]*):[T ]+(.*)/i", + "haystack": "track1.title:TBlah blah blah", + "match": [ + { + "match": "track1.title:TBlah blah blah", + "group1": "track1", + "group2": "title", + "group3": "Blah blah blah" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^.]*)\\.([^:]*):[t ]+(.*)/i", + "haystack": "track1.title:TBlah blah blah", + "match": [ + { + "match": "track1.title:TBlah blah blah", + "group1": "track1", + "group2": "title", + "group3": "Blah blah blah" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-c]+$/", + "haystack": "WXY_^abc", + "match": [ + { + "match": "WXY_^abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[W-c]+$/", + "haystack": "wxy", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-c]+$/i", + "haystack": "WXY_^abc", + "match": [ + { + "match": "WXY_^abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-c]+$/i", + "haystack": "wxy_^ABC", + "match": [ + { + "match": "wxy_^ABC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\x3f-\\x5F]+$/i", + "haystack": "WXY_^abc", + "match": [ + { + "match": "WXY_^abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\x3f-\\x5F]+$/i", + "haystack": "wxy_^ABC", + "match": [ + { + "match": "wxy_^ABC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc$/m", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc$/m", + "haystack": "qqq\\nabc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc$/m", + "haystack": "abc\\nzzz", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc$/m", + "haystack": "qqq\\nabc\\nzzz", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc$/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^abc$/", + "haystack": "qqq\\nabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^abc$/", + "haystack": "abc\\nzzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^abc$/", + "haystack": "qqq\\nabc\\nzzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\Aabc\\Z/m", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\Aabc\\Z/m", + "haystack": "abc\\n", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\Aabc\\Z/m", + "haystack": "qqq\\nabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\Aabc\\Z/m", + "haystack": "abc\\nzzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\Aabc\\Z/m", + "haystack": "qqq\\nabc\\nzzz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\A(.)*\\Z/s", + "haystack": "abc\\ndef", + "match": [ + { + "match": "abc\\x0adef", + "group1": "f" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\A(.)*\\Z/m", + "haystack": "abc\\ndef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:b)|(?::+)/", + "haystack": "b::c", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:b)|(?::+)/", + "haystack": "c::b", + "match": [ + { + "match": "::" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[-az]+/", + "haystack": "az-", + "match": [ + { + "match": "az-" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[-az]+/", + "haystack": "b", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[az-]+/", + "haystack": "za-", + "match": [ + { + "match": "za-" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[az-]+/", + "haystack": "b", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[a\\-z]+/", + "haystack": "a-z", + "match": [ + { + "match": "a-z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[a\\-z]+/", + "haystack": "b", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[a-z]+/", + "haystack": "abcdxyz", + "match": [ + { + "match": "abcdxyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\d-]+/", + "haystack": "12-34", + "match": [ + { + "match": "12-34" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[\\d-]+/", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\x5c/", + "haystack": "\\\\", + "match": [ + { + "match": "\\" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\x20Z/", + "haystack": "the Zoo", + "match": [ + { + "match": " Z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\x20Z/", + "haystack": "Zulu", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1/i", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1/i", + "haystack": "ABCabc", + "match": [ + { + "match": "ABCabc", + "group1": "ABC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1/i", + "haystack": "abcABC", + "match": [ + { + "match": "abcABC", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc$/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc$/", + "haystack": "abc\\n", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/abc$/", + "haystack": "abc\\ndef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\123/", + "haystack": "abc\\x53", + "match": [ + { + "match": "abcS", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\223/", + "haystack": "abc\\x93", + "match": [ + { + "match": "abc\\x93", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\323/", + "haystack": "abc\\xd3", + "match": [ + { + "match": "abc\\xd3", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\100/", + "haystack": "abc\\x40", + "match": [ + { + "match": "abc@", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\100/", + "haystack": "abc\\100", + "match": [ + { + "match": "abc@", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\x400", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\x40\\x30", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\1000", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\100\\x30", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\100\\060", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)\\1000/", + "haystack": "abc\\100\\60", + "match": [ + { + "match": "abc@0", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(A)(B)(C)(D)(E)(F)(G)(H)(I)\\8\\9$/", + "haystack": "ABCDEFGHIHI", + "match": [ + { + "match": "ABCDEFGHIHI", + "group1": "A", + "group2": "B", + "group3": "C", + "group4": "D", + "group5": "E", + "group6": "F", + "group7": "G", + "group8": "H", + "group9": "I" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[A\\8B\\9C]+$/", + "haystack": "A8B9C", + "match": [ + { + "match": "A8B9C" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[A\\8B\\9C]+$/", + "haystack": "A8B9C\\x00", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\\12\\123/", + "haystack": "abcdefghijkllS", + "match": [ + { + "match": "abcdefghijkllS", + "group1": "a", + "group2": "b", + "group3": "c", + "group4": "d", + "group5": "e", + "group6": "f", + "group7": "g", + "group8": "h", + "group9": "i", + "group10": "j", + "group11": "k", + "group12": "l" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\12\\123/", + "haystack": "abcdefghijk\\12S", + "match": [ + { + "match": "abcdefghijk\\x0aS", + "group1": "a", + "group2": "b", + "group3": "c", + "group4": "d", + "group5": "e", + "group6": "f", + "group7": "g", + "group8": "h", + "group9": "i", + "group10": "j", + "group11": "k" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{0}bc/", + "haystack": "bc", + "match": [ + { + "match": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a|(bc)){0,0}?xyz/", + "haystack": "xyz", + "match": [ + { + "match": "xyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc[\\10]de/", + "haystack": "abc\\010de", + "match": [ + { + "match": "abc\\x08de" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc[\\1]de/", + "haystack": "abc\\1de", + "match": [ + { + "match": "abc\\x01de" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc)[\\1]de/", + "haystack": "abc\\1de", + "match": [ + { + "match": "abc\\x01de", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s)a.b/", + "haystack": "a\\nb", + "match": [ + { + "match": "a\\x0ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "baNOTccccd", + "match": [ + { + "match": "baNOTcccc", + "group1": "b", + "group2": "a", + "group3": "NOT", + "group4": "cccc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "baNOTcccd", + "match": [ + { + "match": "baNOTccc", + "group1": "b", + "group2": "a", + "group3": "NOT", + "group4": "ccc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "baNOTccd", + "match": [ + { + "match": "baNOTcc", + "group1": "b", + "group2": "a", + "group3": "NO", + "group4": "Tcc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "bacccd", + "match": [ + { + "match": "baccc", + "group1": "b", + "group2": "a", + "group3": "", + "group4": "ccc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "anything", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "b\\bc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^a])([^\\b])([^c]*)([^d]{3,4})/", + "haystack": "baccd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[^a]/", + "haystack": "Abc", + "match": [ + { + "match": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]/i", + "haystack": "Abc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]+/", + "haystack": "AAAaAbc", + "match": [ + { + "match": "AAA" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]+/i", + "haystack": "AAAaAbc", + "match": [ + { + "match": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]+/", + "haystack": "bbb\\nccc", + "match": [ + { + "match": "bbb\\x0accc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^k]$/", + "haystack": "abc", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[^k]$/", + "haystack": "abk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[^k]{2,3}$/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^k]{2,3}$/", + "haystack": "kbc", + "match": [ + { + "match": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^k]{2,3}$/", + "haystack": "kabc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[^k]{2,3}$/", + "haystack": "abk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[^k]{2,3}$/", + "haystack": "akb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[^k]{2,3}$/", + "haystack": "akk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8,}\\@.+[^k]$/", + "haystack": "12345678\\@a.b.c.d", + "match": [ + { + "match": "12345678@a.b.c.d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8,}\\@.+[^k]$/", + "haystack": "123456789\\@x.y.z", + "match": [ + { + "match": "123456789@x.y.z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\d{8,}\\@.+[^k]$/", + "haystack": "12345678\\@x.y.uk", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^\\d{8,}\\@.+[^k]$/", + "haystack": "1234567\\@a.b.c.d", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a)\\1{8,}/", + "haystack": "aaaaaaaaa", + "match": [ + { + "match": "aaaaaaaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a)\\1{8,}/", + "haystack": "aaaaaaaaaa", + "match": [ + { + "match": "aaaaaaaaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a)\\1{8,}/", + "haystack": "aaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[^a]/", + "haystack": "aaaabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]/", + "haystack": "aaAabcd", + "match": [ + { + "match": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]/i", + "haystack": "aaaabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^a]/i", + "haystack": "aaAabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^az]/", + "haystack": "aaaabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^az]/", + "haystack": "aaAabcd", + "match": [ + { + "match": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^az]/i", + "haystack": "aaaabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[^az]/i", + "haystack": "aaAabcd", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\000\\001\\002\\003\\004\\005\\006\\007\\010\\011\\012\\013\\014\\015\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037\\040\\041\\042\\043\\044\\045\\046\\047\\050\\051\\052\\053\\054\\055\\056\\057\\060\\061\\062\\063\\064\\065\\066\\067\\070\\071\\072\\073\\074\\075\\076\\077\\100\\101\\102\\103\\104\\105\\106\\107\\110\\111\\112\\113\\114\\115\\116\\117\\120\\121\\122\\123\\124\\125\\126\\127\\130\\131\\132\\133\\134\\135\\136\\137\\140\\141\\142\\143\\144\\145\\146\\147\\150\\151\\152\\153\\154\\155\\156\\157\\160\\161\\162\\163\\164\\165\\166\\167\\170\\171\\172\\173\\174\\175\\176\\177\\200\\201\\202\\203\\204\\205\\206\\207\\210\\211\\212\\213\\214\\215\\216\\217\\220\\221\\222\\223\\224\\225\\226\\227\\230\\231\\232\\233\\234\\235\\236\\237\\240\\241\\242\\243\\244\\245\\246\\247\\250\\251\\252\\253\\254\\255\\256\\257\\260\\261\\262\\263\\264\\265\\266\\267\\270\\271\\272\\273\\274\\275\\276\\277\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\317\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\337\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\\376\\377/", + "haystack": "\\000\\001\\002\\003\\004\\005\\006\\007\\010\\011\\012\\013\\014\\015\\016\\017\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037\\040\\041\\042\\043\\044\\045\\046\\047\\050\\051\\052\\053\\054\\055\\056\\057\\060\\061\\062\\063\\064\\065\\066\\067\\070\\071\\072\\073\\074\\075\\076\\077\\100\\101\\102\\103\\104\\105\\106\\107\\110\\111\\112\\113\\114\\115\\116\\117\\120\\121\\122\\123\\124\\125\\126\\127\\130\\131\\132\\133\\134\\135\\136\\137\\140\\141\\142\\143\\144\\145\\146\\147\\150\\151\\152\\153\\154\\155\\156\\157\\160\\161\\162\\163\\164\\165\\166\\167\\170\\171\\172\\173\\174\\175\\176\\177\\200\\201\\202\\203\\204\\205\\206\\207\\210\\211\\212\\213\\214\\215\\216\\217\\220\\221\\222\\223\\224\\225\\226\\227\\230\\231\\232\\233\\234\\235\\236\\237\\240\\241\\242\\243\\244\\245\\246\\247\\250\\251\\252\\253\\254\\255\\256\\257\\260\\261\\262\\263\\264\\265\\266\\267\\270\\271\\272\\273\\274\\275\\276\\277\\300\\301\\302\\303\\304\\305\\306\\307\\310\\311\\312\\313\\314\\315\\316\\317\\320\\321\\322\\323\\324\\325\\326\\327\\330\\331\\332\\333\\334\\335\\336\\337\\340\\341\\342\\343\\344\\345\\346\\347\\350\\351\\352\\353\\354\\355\\356\\357\\360\\361\\362\\363\\364\\365\\366\\367\\370\\371\\372\\373\\374\\375\\376\\377", + "match": [ + { + "match": "\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\x7f\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/P[^*]TAIRE[^*]{1,6}?LL/", + "haystack": "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx", + "match": [ + { + "match": "PSTAIREISLL" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/P[^*]TAIRE[^*]{1,}?LL/", + "haystack": "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx", + "match": [ + { + "match": "PSTAIREISLL" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\.\\d\\d[1-9]?)\\d+/", + "haystack": "1.230003938", + "match": [ + { + "match": ".230003938", + "group1": ".23" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\.\\d\\d[1-9]?)\\d+/", + "haystack": "1.875000282", + "match": [ + { + "match": ".875000282", + "group1": ".875" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\.\\d\\d[1-9]?)\\d+/", + "haystack": "1.235", + "match": [ + { + "match": ".235", + "group1": ".23" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\.\\d\\d((?=0)|\\d(?=\\d)))/", + "haystack": "1.230003938", + "match": [ + { + "match": ".23", + "group1": ".23", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\.\\d\\d((?=0)|\\d(?=\\d)))/", + "haystack": "1.875000282", + "match": [ + { + "match": ".875", + "group1": ".875", + "group2": "5" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(\\.\\d\\d((?=0)|\\d(?=\\d)))/", + "haystack": "1.235", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?)b/", + "haystack": "ab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\b(foo)\\s+(\\w+)/i", + "haystack": "Food is on the foo table", + "match": [ + { + "match": "foo table", + "group1": "foo", + "group2": "table" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/foo(.*)bar/", + "haystack": "The food is under the bar in the barn.", + "match": [ + { + "match": "food is under the bar in the bar", + "group1": "d is under the bar in the " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/foo(.*?)bar/", + "haystack": "The food is under the bar in the barn.", + "match": [ + { + "match": "food is under the bar", + "group1": "d is under the " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)(\\d*)/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: 53147", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)(\\d+)/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: 5314", + "group2": "7" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*?)(\\d*)/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "", + "group1": "", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*?)(\\d+)/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2", + "group1": "I have ", + "group2": "2" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)(\\d+)$/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: 5314", + "group2": "7" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*?)(\\d+)$/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: ", + "group2": "53147" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)\\b(\\d+)$/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: ", + "group2": "53147" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*\\D)(\\d+)$/", + "haystack": "I have 2 numbers: 53147", + "match": [ + { + "match": "I have 2 numbers: 53147", + "group1": "I have 2 numbers: ", + "group2": "53147" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\D*(?!123)/", + "haystack": "ABC123", + "match": [ + { + "match": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(\\D*)(?=\\d)(?!123)/", + "haystack": "ABC445", + "match": [ + { + "match": "ABC", + "group1": "ABC" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(\\D*)(?=\\d)(?!123)/", + "haystack": "ABC123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "W46]789", + "match": [ + { + "match": "W46]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "-46]789", + "match": [ + { + "match": "-46]" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[W-]46]/", + "haystack": "Wall", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "Zebra", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "42", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "[abcd]", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-]46]/", + "haystack": "]abcd[", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "W46]789", + "match": [ + { + "match": "W" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "Wall", + "match": [ + { + "match": "W" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "Zebra", + "match": [ + { + "match": "Z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "Xylophone", + "match": [ + { + "match": "X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "42", + "match": [ + { + "match": "4" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "[abcd]", + "match": [ + { + "match": "[" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "]abcd[", + "match": [ + { + "match": "]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "\\\\backslash", + "match": [ + { + "match": "\\" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[W-\\]46]/", + "haystack": "-46]789", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[W-\\]46]/", + "haystack": "well", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\d\\d\\/\\d\\d\\/\\d\\d\\d\\d/", + "haystack": "01/01/2000", + "match": [ + { + "match": "01/01/2000" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/word (?:[a-zA-Z0-9]+ ){0,10}otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark otherword", + "match": [ + { + "match": "word cat dog elephant mussel cow horse canary baboon snake shark otherword" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/word (?:[a-zA-Z0-9]+ ){0,10}otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/word (?:[a-zA-Z0-9]+ ){0,300}otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,0}/", + "haystack": "bcd", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,0}/", + "haystack": "abc", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,0}/", + "haystack": "aab", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,1}/", + "haystack": "bcd", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,1}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,1}/", + "haystack": "aab", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,2}/", + "haystack": "bcd", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,2}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,2}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,3}/", + "haystack": "bcd", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,3}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,3}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,3}/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,}/", + "haystack": "bcd", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,}/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){0,}/", + "haystack": "aaaaaaaa", + "match": [ + { + "match": "aaaaaaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,1}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,1}/", + "haystack": "aab", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a){1,1}/", + "haystack": "bcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,2}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,2}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a){1,2}/", + "haystack": "bcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,3}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,3}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,3}/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a){1,3}/", + "haystack": "bcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,}/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,}/", + "haystack": "aab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,}/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){1,}/", + "haystack": "aaaaaaaa", + "match": [ + { + "match": "aaaaaaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a){1,}/", + "haystack": "bcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/.*\\.gif/", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "bib.gif" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.{0,}\\.gif/", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "bib.gif" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*\\.gif/m", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "bib.gif" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*\\.gif/s", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "borfle\\x0abib.gif" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*\\.gif/ms", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "borfle\\x0abib.gif" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "no" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/m", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "borfle" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/s", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "borfle\\x0abib.gif\\x0ano" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/ms", + "haystack": "borfle\\nbib.gif\\nno", + "match": [ + { + "match": "borfle\\x0abib.gif\\x0ano" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/", + "haystack": "borfle\\nbib.gif\\nno\\n", + "match": [ + { + "match": "no" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/m", + "haystack": "borfle\\nbib.gif\\nno\\n", + "match": [ + { + "match": "borfle" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/s", + "haystack": "borfle\\nbib.gif\\nno\\n", + "match": [ + { + "match": "borfle\\x0abib.gif\\x0ano\\x0a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*$/ms", + "haystack": "borfle\\nbib.gif\\nno\\n", + "match": [ + { + "match": "borfle\\x0abib.gif\\x0ano\\x0a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "1234X", + "group1": "1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/", + "haystack": "BarFoo", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(.*X|^B)/", + "haystack": "abcde\\nBar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/m", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "1234X", + "group1": "1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/m", + "haystack": "BarFoo", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/m", + "haystack": "abcde\\nBar", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/s", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "abcde\\x0a1234X", + "group1": "abcde\\x0a1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/s", + "haystack": "BarFoo", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(.*X|^B)/s", + "haystack": "abcde\\nBar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/ms", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "abcde\\x0a1234X", + "group1": "abcde\\x0a1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/ms", + "haystack": "BarFoo", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*X|^B)/ms", + "haystack": "abcde\\nBar", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s)(.*X|^B)/", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "abcde\\x0a1234X", + "group1": "abcde\\x0a1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s)(.*X|^B)/", + "haystack": "BarFoo", + "match": [ + { + "match": "B", + "group1": "B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?s)(.*X|^B)/", + "haystack": "abcde\\nBar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?s:.*X|^B)/", + "haystack": "abcde\\n1234Xyz", + "match": [ + { + "match": "abcde\\x0a1234X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s:.*X|^B)/", + "haystack": "BarFoo", + "match": [ + { + "match": "B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?s:.*X|^B)/", + "haystack": "abcde\\nBar", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^.*B/", + "haystack": "abc\\nB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?s)^.*B/", + "haystack": "abc\\nB", + "match": [ + { + "match": "abc\\x0aB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?m)^.*B/", + "haystack": "abc\\nB", + "match": [ + { + "match": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?ms)^.*B/", + "haystack": "abc\\nB", + "match": [ + { + "match": "abc\\x0aB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?ms)^B/", + "haystack": "abc\\nB", + "match": [ + { + "match": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s)B$/", + "haystack": "B\\n", + "match": [ + { + "match": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/", + "haystack": "123456654321", + "match": [ + { + "match": "123456654321" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d\\d/", + "haystack": "123456654321", + "match": [ + { + "match": "123456654321" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]/", + "haystack": "123456654321", + "match": [ + { + "match": "123456654321" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[abc]{12}/", + "haystack": "abcabcabcabc", + "match": [ + { + "match": "abcabcabcabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[a-c]{12}/", + "haystack": "abcabcabcabc", + "match": [ + { + "match": "abcabcabcabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a|b|c){12}/", + "haystack": "abcabcabcabc", + "match": [ + { + "match": "abcabcabcabc", + "group1": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[abcdefghijklmnopqrstuvwxy0123456789]/", + "haystack": "n", + "match": [ + { + "match": "n" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[abcdefghijklmnopqrstuvwxy0123456789]/", + "haystack": "z", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/abcde{0,0}/", + "haystack": "abcd", + "match": [ + { + "match": "abcd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/abcde{0,0}/", + "haystack": "abce", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ab[cd]{0,0}e/", + "haystack": "abe", + "match": [ + { + "match": "abe" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ab[cd]{0,0}e/", + "haystack": "abcde", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ab(c){0,0}d/", + "haystack": "abd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ab(c){0,0}d/", + "haystack": "abcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(b*)/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(b*)/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(b*)/", + "haystack": "abbbb", + "match": [ + { + "match": "abbbb", + "group1": "bbbb" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(b*)/", + "haystack": "bbbbb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ab\\d{0}e/", + "haystack": "abe", + "match": [ + { + "match": "abe" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ab\\d{0}e/", + "haystack": "ab1e", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\"([^\\\\\"]+|\\\\.)*\"/", + "haystack": "the \\\"quick\\\" brown fox", + "match": [ + { + "match": "\"quick\"", + "group1": "quick" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\"([^\\\\\"]+|\\\\.)*\"/", + "haystack": "\\\"the \\\\\\\"quick\\\\\\\" brown fox\\\"", + "match": [ + { + "match": "\"the \\\"quick\\\" brown fox\"", + "group1": " brown fox" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.*?/g", + "haystack": "abc", + "match": [ + { + "match": "" + }, + { + "match": "a" + }, + { + "match": "" + }, + { + "match": "b" + }, + { + "match": "" + }, + { + "match": "c" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\b/g", + "haystack": "abc", + "match": [ + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\b/g", + "haystack": "abc", + "match": [ + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?#)/g", + "haystack": "abc", + "match": [ + { + "match": "" + }, + { + "match": "" + }, + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/]{0,})>]{0,})>([\\d]{0,}\\.)(.*)((
([\\w\\W\\s\\d][^<>]{0,})|[\\s]{0,}))<\\/a><\\/TD>]{0,})>([\\w\\W\\s\\d][^<>]{0,})<\\/TD>]{0,})>([\\w\\W\\s\\d][^<>]{0,})<\\/TD><\\/TR>/is", + "haystack": "43.
Word Processor
(N-1286)
Lega lstaff.comCA - Statewide", + "match": [ + { + "match": "43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide", + "group1": " BGCOLOR='#DBE9E9'", + "group2": " align=left valign=top", + "group3": "43.", + "group4": "Word Processor
(N-1286)", + "group5": "", + "group6": "", + "group8": " align=left valign=top", + "group9": "Lega lstaff.com", + "group10": " align=left valign=top", + "group11": "CA - Statewide" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a[^a]b/", + "haystack": "acb", + "match": [ + { + "match": "acb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a[^a]b/", + "haystack": "a\\nb", + "match": [ + { + "match": "a\\x0ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a.b/", + "haystack": "acb", + "match": [ + { + "match": "acb" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a.b/", + "haystack": "a\\nb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a[^a]b/s", + "haystack": "acb", + "match": [ + { + "match": "acb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a[^a]b/s", + "haystack": "a\\nb", + "match": [ + { + "match": "a\\x0ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a.b/s", + "haystack": "acb", + "match": [ + { + "match": "acb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a.b/s", + "haystack": "a\\nb", + "match": [ + { + "match": "a\\x0ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bac", + "match": [ + { + "match": "bac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbac", + "match": [ + { + "match": "bbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbbac", + "match": [ + { + "match": "bbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbbbac", + "match": [ + { + "match": "bbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+?|a){1,2}?c/", + "haystack": "bbbbbac", + "match": [ + { + "match": "bbbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}?c/", + "haystack": "bac", + "match": [ + { + "match": "bac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}?c/", + "haystack": "bbac", + "match": [ + { + "match": "bbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}?c/", + "haystack": "bbbac", + "match": [ + { + "match": "bbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}?c/", + "haystack": "bbbbac", + "match": [ + { + "match": "bbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(b+|a){1,2}?c/", + "haystack": "bbbbbac", + "match": [ + { + "match": "bbbbbac", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!\\A)x/m", + "haystack": "a\\bx\\n", + "match": [ + { + "match": "x" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!\\A)x/m", + "haystack": "a\\nx\\n", + "match": [ + { + "match": "x" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?!\\A)x/m", + "haystack": "x\\nb\\n", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(A|B)*?CD/", + "haystack": "CD", + "match": [ + { + "match": "CD" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(A|B)*CD/", + "haystack": "CD", + "match": [ + { + "match": "CD" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(AB)*?\\1/", + "haystack": "ABABAB", + "match": [ + { + "match": "ABAB", + "group1": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(AB)*\\1/", + "haystack": "ABABAB", + "match": [ + { + "match": "ABABAB", + "group1": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?.*\\/)foo/", + "haystack": "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo", + "match": [ + { + "match": "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>.*\\/)foo/", + "haystack": "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>(\\.\\d\\d[1-9]?))\\d+/", + "haystack": "1.230003938", + "match": [ + { + "match": ".230003938", + "group1": ".23" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(\\.\\d\\d[1-9]?))\\d+/", + "haystack": "1.875000282", + "match": [ + { + "match": ".875000282", + "group1": ".875" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>(\\.\\d\\d[1-9]?))\\d+/", + "haystack": "1.235", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^((?>\\w+)|(?>\\s+))*$/", + "haystack": "now is the time for all good men to come to the aid of the party", + "match": [ + { + "match": "now is the time for all good men to come to the aid of the party", + "group1": "party" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^((?>\\w+)|(?>\\s+))*$/", + "haystack": "this is not a line with only words and spaces!", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(\\d+)(\\w)/", + "haystack": "12345a", + "match": [ + { + "match": "12345a", + "group1": "12345", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\d+)(\\w)/", + "haystack": "12345+", + "match": [ + { + "match": "12345", + "group1": "1234", + "group2": "5" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>\\d+))(\\w)/", + "haystack": "12345a", + "match": [ + { + "match": "12345a", + "group1": "12345", + "group2": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/((?>\\d+))(\\w)/", + "haystack": "12345+", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>a+)b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a+)b)/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(a+))b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>b)+/", + "haystack": "aaabbbccc", + "match": [ + { + "match": "bbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a+|b+|c+)*c/", + "haystack": "aaabbbbccccd", + "match": [ + { + "match": "aaabbbbc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>[^()]+)|\\([^()]*\\))+/", + "haystack": "((abc(ade)ufh()()x", + "match": [ + { + "match": "abc(ade)ufh()()x", + "group1": "x" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\(((?>[^()]+)|\\([^()]+\\))+\\)/", + "haystack": "(abc)", + "match": [ + { + "match": "(abc)", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\(((?>[^()]+)|\\([^()]+\\))+\\)/", + "haystack": "(abc(def)xyz)", + "match": [ + { + "match": "(abc(def)xyz)", + "group1": "xyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\(((?>[^()]+)|\\([^()]+\\))+\\)/", + "haystack": "((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?-i)b/i", + "haystack": "ab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?-i)b/i", + "haystack": "Ab", + "match": [ + { + "match": "Ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?-i)b/i", + "haystack": "aB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?-i)b/i", + "haystack": "AB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a (?x)b c)d e/", + "haystack": "a bcd e", + "match": [ + { + "match": "a bcd e", + "group1": "a bc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a (?x)b c)d e/", + "haystack": "a b cd e", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a (?x)b c)d e/", + "haystack": "abcd e", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a (?x)b c)d e/", + "haystack": "a bcde", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a b(?x)c d (?-x)e f)/", + "haystack": "a bcde f", + "match": [ + { + "match": "a bcde f", + "group1": "a bcde f" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a b(?x)c d (?-x)e f)/", + "haystack": "abcdef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "aBc", + "match": [ + { + "match": "aBc", + "group1": "aB" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a(?i)b)c/", + "haystack": "abC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "aBC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "Abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "ABc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "ABC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)b)c/", + "haystack": "AbC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)c/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)c/", + "haystack": "aBc", + "match": [ + { + "match": "aBc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?i:b)c/", + "haystack": "ABC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)c/", + "haystack": "abC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)c/", + "haystack": "aBC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)*c/", + "haystack": "aBc", + "match": [ + { + "match": "aBc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)*c/", + "haystack": "aBBc", + "match": [ + { + "match": "aBBc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?i:b)*c/", + "haystack": "aBC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?i:b)*c/", + "haystack": "aBBC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?=b(?i)c)\\w\\wd/", + "haystack": "abcd", + "match": [ + { + "match": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?=b(?i)c)\\w\\wd/", + "haystack": "abCd", + "match": [ + { + "match": "abCd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?=b(?i)c)\\w\\wd/", + "haystack": "aBCd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?=b(?i)c)\\w\\wd/", + "haystack": "abcD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?s-i:more.*than).*million/i", + "haystack": "more than million", + "match": [ + { + "match": "more than million" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s-i:more.*than).*million/i", + "haystack": "more than MILLION", + "match": [ + { + "match": "more than MILLION" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s-i:more.*than).*million/i", + "haystack": "more \\n than Million", + "match": [ + { + "match": "more \\x0a than Million" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?s-i:more.*than).*million/i", + "haystack": "MORE THAN MILLION", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?s-i:more.*than).*million/i", + "haystack": "more \\n than \\n million", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?s-i)more.*than).*million/i", + "haystack": "more than million", + "match": [ + { + "match": "more than million" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?s-i)more.*than).*million/i", + "haystack": "more than MILLION", + "match": [ + { + "match": "more than MILLION" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?s-i)more.*than).*million/i", + "haystack": "more \\n than Million", + "match": [ + { + "match": "more \\x0a than Million" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:(?s-i)more.*than).*million/i", + "haystack": "MORE THAN MILLION", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?s-i)more.*than).*million/i", + "haystack": "more \\n than \\n million", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "aBbc", + "match": [ + { + "match": "aBbc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "aBBc", + "match": [ + { + "match": "aBBc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "Abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "abAb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>a(?i)b+)+c/", + "haystack": "abbC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=a(?i)b)\\w\\wc/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=a(?i)b)\\w\\wc/", + "haystack": "aBc", + "match": [ + { + "match": "aBc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=a(?i)b)\\w\\wc/", + "haystack": "Ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=a(?i)b)\\w\\wc/", + "haystack": "abC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=a(?i)b)\\w\\wc/", + "haystack": "aBC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(?i)b)(\\w\\w)c/", + "haystack": "abxxc", + "match": [ + { + "match": "xxc", + "group1": "xx" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(?i)b)(\\w\\w)c/", + "haystack": "aBxxc", + "match": [ + { + "match": "xxc", + "group1": "xx" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=a(?i)b)(\\w\\w)c/", + "haystack": "Abxxc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(?i)b)(\\w\\w)c/", + "haystack": "ABxxc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(?i)b)(\\w\\w)c/", + "haystack": "abxxC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(a)|b)(?(1)A|B)/", + "haystack": "aA", + "match": [ + { + "match": "aA", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(a)|b)(?(1)A|B)/", + "haystack": "bB", + "match": [ + { + "match": "bB" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:(a)|b)(?(1)A|B)/", + "haystack": "aB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(a)|b)(?(1)A|B)/", + "haystack": "bA", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a)?(?(1)a|b)+$/", + "haystack": "aa", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)?(?(1)a|b)+$/", + "haystack": "b", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)?(?(1)a|b)+$/", + "haystack": "bb", + "match": [ + { + "match": "bb" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a)?(?(1)a|b)+$/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=abc)\\w{3}:|\\d\\d)/", + "haystack": "abc:", + "match": [ + { + "match": "abc:" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=abc)\\w{3}:|\\d\\d)/", + "haystack": "12", + "match": [ + { + "match": "12" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=abc)\\w{3}:|\\d\\d)/", + "haystack": "123", + "match": [ + { + "match": "12" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?(?=abc)\\w{3}:|\\d\\d)/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!abc)\\d\\d|\\w{3}:)$/", + "haystack": "abc:", + "match": [ + { + "match": "abc:" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!abc)\\d\\d|\\w{3}:)$/", + "haystack": "12", + "match": [ + { + "match": "12" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?(?!abc)\\d\\d|\\w{3}:)$/", + "haystack": "123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!abc)\\d\\d|\\w{3}:)$/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(?<=foo)bar|cat)/", + "haystack": "foobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?<=foo)bar|cat)/", + "haystack": "cat", + "match": [ + { + "match": "cat" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?<=foo)bar|cat)/", + "haystack": "fcat", + "match": [ + { + "match": "cat" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?<=foo)bar|cat)/", + "haystack": "focat", + "match": [ + { + "match": "cat" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?(?<=foo)bar|cat)/", + "haystack": "foocat", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(?a*)*/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a*)*/", + "haystack": "aa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a*)*/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc|)+/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc|)+/", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc|)+/", + "haystack": "abcabcabc", + "match": [ + { + "match": "abcabcabc", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(abc|)+/", + "haystack": "xyz", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([a]*)*/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([a]*)*/", + "haystack": "aaaaa", + "match": [ + { + "match": "aaaaa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*)*/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*)*/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*)*/", + "haystack": "ababab", + "match": [ + { + "match": "ababab", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*)*/", + "haystack": "aaaabcde", + "match": [ + { + "match": "aaaab", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*)*/", + "haystack": "bbbb", + "match": [ + { + "match": "bbbb", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*)*/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*)*/", + "haystack": "bbbb", + "match": [ + { + "match": "bbbb", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*)*/", + "haystack": "aaa", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^ab]*)*/", + "haystack": "cccc", + "match": [ + { + "match": "cccc", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^ab]*)*/", + "haystack": "abab", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([a]*?)*/", + "haystack": "a", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([a]*?)*/", + "haystack": "aaaa", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*?)*/", + "haystack": "a", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*?)*/", + "haystack": "b", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*?)*/", + "haystack": "abab", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([ab]*?)*/", + "haystack": "baba", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*?)*/", + "haystack": "b", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*?)*/", + "haystack": "bbbb", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^a]*?)*/", + "haystack": "aaa", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^ab]*?)*/", + "haystack": "c", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^ab]*?)*/", + "haystack": "cccc", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^ab]*?)*/", + "haystack": "baba", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a*)*/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a*)*/", + "haystack": "aaabcde", + "match": [ + { + "match": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a*))*/", + "haystack": "aaaaa", + "match": [ + { + "match": "aaaaa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a*))*/", + "haystack": "aabbaa", + "match": [ + { + "match": "aa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a*?))*/", + "haystack": "aaaaa", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a*?))*/", + "haystack": "aabbaa", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) /x", + "haystack": "12-sep-98", + "match": [ + { + "match": "12-sep-98" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) /x", + "haystack": "12-09-98", + "match": [ + { + "match": "12-09-98" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?(?=[^a-z]+[a-z]) \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} ) /x", + "haystack": "sep-12-98", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=(foo))bar\\1/", + "haystack": "foobarfoo", + "match": [ + { + "match": "barfoo", + "group1": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(foo))bar\\1/", + "haystack": "foobarfootling", + "match": [ + { + "match": "barfoo", + "group1": "foo" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=(foo))bar\\1/", + "haystack": "foobar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=(foo))bar\\1/", + "haystack": "barfoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "saturday", + "match": [ + { + "match": "saturday" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "sunday", + "match": [ + { + "match": "sunday" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "Saturday", + "match": [ + { + "match": "Saturday" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "Sunday", + "match": [ + { + "match": "Sunday" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "SATURDAY", + "match": [ + { + "match": "SATURDAY" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "SUNDAY", + "match": [ + { + "match": "SUNDAY" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:saturday|sunday)/", + "haystack": "SunDay", + "match": [ + { + "match": "SunDay" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "abcx", + "match": [ + { + "match": "abcx", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "aBCx", + "match": [ + { + "match": "aBCx", + "group1": "aBC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "bbx", + "match": [ + { + "match": "bbx", + "group1": "bb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "BBx", + "match": [ + { + "match": "BBx", + "group1": "BB" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "abcX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "aBCX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "bbX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a(?i)bc|BB)x/", + "haystack": "BBX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group1": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "aC", + "match": [ + { + "match": "aC", + "group1": "aC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "bD", + "match": [ + { + "match": "bD", + "group1": "bD" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "elephant", + "match": [ + { + "match": "e", + "group1": "e" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "Europe", + "match": [ + { + "match": "E", + "group1": "E" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "frog", + "match": [ + { + "match": "f", + "group1": "f" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "France", + "match": [ + { + "match": "F", + "group1": "F" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^([ab](?i)[cd]|[ef])/", + "haystack": "Africa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "aBd", + "match": [ + { + "match": "aBd", + "group1": "aBd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "xy", + "match": [ + { + "match": "xy", + "group1": "xy" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "xY", + "match": [ + { + "match": "xY", + "group1": "xY" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "zebra", + "match": [ + { + "match": "z", + "group1": "z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "Zambesi", + "match": [ + { + "match": "Z", + "group1": "Z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "aCD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/", + "haystack": "XY", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=foo\\n)^bar/m", + "haystack": "foo\\nbar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=foo\\n)^bar/m", + "haystack": "bar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=foo\\n)^bar/m", + "haystack": "baz\\nbar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=(?]&/", + "haystack": "<&OUT", + "match": [ + { + "match": "<&" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a\\1?){4}$/", + "haystack": "aaaaaaaaaa", + "match": [ + { + "match": "aaaaaaaaaa", + "group1": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a\\1?){4}$/", + "haystack": "AB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a\\1?){4}$/", + "haystack": "aaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a\\1?){4}$/", + "haystack": "aaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a(?(1)\\1)){4}$/", + "haystack": "aaaaaaaaaa", + "match": [ + { + "match": "aaaaaaaaaa", + "group1": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a(?(1)\\1)){4}$/", + "haystack": "aaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a(?(1)\\1)){4}$/", + "haystack": "aaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a)b/", + "haystack": "ab", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=a)b/", + "haystack": "cb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a)b/", + "haystack": "b", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?a+)b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([[:]+)/", + "haystack": "a:[b]:", + "match": [ + { + "match": ":[", + "group1": ":[" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([[=]+)/", + "haystack": "a=[b]=", + "match": [ + { + "match": "=[", + "group1": "=[" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([[.]+)/", + "haystack": "a.[b].", + "match": [ + { + "match": ".[", + "group1": ".[" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a+)b)/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(a+))b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>[^()]+)|\\([^()]*\\))+/", + "haystack": "((abc(ade)ufh()()x", + "match": [ + { + "match": "abc(ade)ufh()()x", + "group1": "x" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a\\Z/", + "haystack": "aaab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a\\Z/", + "haystack": "a\\nb\\n", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/b\\Z/", + "haystack": "a\\nb\\n", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/b\\Z/", + "haystack": "a\\nb", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/b\\z/", + "haystack": "a\\nb", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a-b", + "match": [ + { + "match": "a-b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "0-9", + "match": [ + { + "match": "0-9", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a.b", + "match": [ + { + "match": "a.b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "5.6.7", + "match": [ + { + "match": "5.6.7", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "the.quick.brown.fox", + "match": [ + { + "match": "the.quick.brown.fox", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a100.b200.300c", + "match": [ + { + "match": "a100.b200.300c", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "12-ab.1245", + "match": [ + { + "match": "12-ab.1245", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "\\", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": ".a", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "-a", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a-", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a.", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a_b", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a.-", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "a..", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "ab..bc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "the.quick.brown.fox-", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "the.quick.brown.fox.", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "the.quick.brown.fox_", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>(?(1)\\.|())[^\\W_](?>[a-z0-9-]*[^\\W_])?)+$/", + "haystack": "the.quick.brown.fox+", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>.*)(?<=(abcd|wxyz))/", + "haystack": "alphabetabcd", + "match": [ + { + "match": "alphabetabcd", + "group1": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*)(?<=(abcd|wxyz))/", + "haystack": "endingwxyz", + "match": [ + { + "match": "endingwxyz", + "group1": "wxyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>.*)(?<=(abcd|wxyz))/", + "haystack": "a rather long string that doesn't end with one of them", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark otherword", + "match": [ + { + "match": "word cat dog elephant mussel cow horse canary baboon snake shark otherword" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/word (?>[a-zA-Z0-9]+ ){0,30}otherword/", + "haystack": "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\d{3}(?!999))foo/", + "haystack": "999foo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\d{3}(?!999))foo/", + "haystack": "123999foo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=\\d{3}(?!999))foo/", + "haystack": "123abcfoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=(?!...999)\\d{3})foo/", + "haystack": "999foo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(?!...999)\\d{3})foo/", + "haystack": "123999foo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=(?!...999)\\d{3})foo/", + "haystack": "123abcfoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\d{3}(?!999)...)foo/", + "haystack": "123abcfoo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\d{3}(?!999)...)foo/", + "haystack": "123456foo", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=\\d{3}(?!999)...)foo/", + "haystack": "123999foo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\d{3}...)(?\\s*)=(?>\\s*) # find
\\s*)=(?>\\s*) # find \\s*)=(?>\\s*) # find Z)+|A)*/", + "haystack": "ZABCDEFG", + "match": [ + { + "match": "ZA", + "group1": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>)+|A)*/", + "haystack": "ZABCDEFG", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a*/g", + "haystack": "abbab", + "match": [ + { + "match": "a" + }, + { + "match": "" + }, + { + "match": "" + }, + { + "match": "a" + }, + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[[:space:]]+/", + "haystack": "> \\x09\\x0a\\x0c\\x0d\\x0b<", + "match": [ + { + "match": " \\x09\\x0a\\x0c\\x0d\\x0b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[[:blank:]]+/", + "haystack": "> \\x09\\x0a\\x0c\\x0d\\x0b<", + "match": [ + { + "match": " \\x09" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\s]+/", + "haystack": "> \\x09\\x0a\\x0c\\x0d\\x0b<", + "match": [ + { + "match": " \\x09\\x0a\\x0c\\x0d\\x0b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\s+/", + "haystack": "> \\x09\\x0a\\x0c\\x0d\\x0b<", + "match": [ + { + "match": " \\x09\\x0a\\x0c\\x0d\\x0b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a\u000bb/x", + "haystack": "ab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!\\A)x/m", + "haystack": "a\\nxb\\n", + "match": [ + { + "match": "x" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?!^)x/m", + "haystack": "a\\nxb\\n", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/abc\\Qabc\\Eabc/", + "haystack": "abcabcabc", + "match": [ + { + "match": "abcabcabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc\\Q(*+|\\Eabc/", + "haystack": "abc(*+|abc", + "match": [ + { + "match": "abc(*+|abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ abc\\Q abc\\Eabc/x", + "haystack": "abc abcabc", + "match": [ + { + "match": "abc abcabc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ abc\\Q abc\\Eabc/x", + "haystack": "abcabcabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/abc#comment\n \\Q#not comment\n literal\\E/x", + "haystack": "abc#not comment\\n literal", + "match": [ + { + "match": "abc#not comment\\x0a literal" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc#comment\n \\Q#not comment\n literal/x", + "haystack": "abc#not comment\\n literal", + "match": [ + { + "match": "abc#not comment\\x0a literal" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc#comment\n \\Q#not comment\n literal\\E #more comment\n /x", + "haystack": "abc#not comment\\n literal", + "match": [ + { + "match": "abc#not comment\\x0a literal" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc#comment\n \\Q#not comment\n literal\\E #more comment/x", + "haystack": "abc#not comment\\n literal", + "match": [ + { + "match": "abc#not comment\\x0a literal" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\Qabc\\$xyz\\E/", + "haystack": "abc\\\\\\$xyz", + "match": [ + { + "match": "abc\\$xyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\Qabc\\E\\$\\Qxyz\\E/", + "haystack": "abc\\$xyz", + "match": [ + { + "match": "abc$xyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\Gabc/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\Gabc/", + "haystack": "xyzabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\Gabc./g", + "haystack": "abc1abc2xyzabc3", + "match": [ + { + "match": "abc1" + }, + { + "match": "abc2" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc./g", + "haystack": "abc1abc2xyzabc3", + "match": [ + { + "match": "abc1" + }, + { + "match": "abc2" + }, + { + "match": "abc3" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?x: b c )d/", + "haystack": "XabcdY", + "match": [ + { + "match": "abcd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?x: b c )d/", + "haystack": "Xa b c d Y", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?x)x y z | a b c)/", + "haystack": "XabcY", + "match": [ + { + "match": "abc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?x)x y z | a b c)/", + "haystack": "AxyzB", + "match": [ + { + "match": "xyz", + "group1": "xyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i)AB(?-i)C/", + "haystack": "XabCY", + "match": [ + { + "match": "abC" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?i)AB(?-i)C/", + "haystack": "XabcY", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "abCE", + "match": [ + { + "match": "abCE", + "group1": "abC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "DE", + "match": [ + { + "match": "DE", + "group1": "D" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "abcE", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "abCe", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "dE", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?i)AB(?-i)C|D)E/", + "haystack": "De", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(.*)\\d+\\1/", + "haystack": "abc123abc", + "match": [ + { + "match": "abc123abc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)\\d+\\1/", + "haystack": "abc123bc", + "match": [ + { + "match": "bc123bc", + "group1": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)\\d+\\1/s", + "haystack": "abc123abc", + "match": [ + { + "match": "abc123abc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(.*)\\d+\\1/s", + "haystack": "abc123bc", + "match": [ + { + "match": "bc123bc", + "group1": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((.*))\\d+\\1/", + "haystack": "abc123abc", + "match": [ + { + "match": "abc123abc", + "group1": "abc", + "group2": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((.*))\\d+\\1/", + "haystack": "abc123bc", + "match": [ + { + "match": "bc123bc", + "group1": "bc", + "group2": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123::a123", + "match": [ + { + "match": "a123::a123", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:b342::abcd", + "match": [ + { + "match": "a123:b342::abcd", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:b342::324e:abcd", + "match": [ + { + "match": "a123:b342::324e:abcd", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:ddde:b342::324e:abcd", + "match": [ + { + "match": "a123:ddde:b342::324e:abcd", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:ddde:b342::324e:dcba:abcd", + "match": [ + { + "match": "a123:ddde:b342::324e:dcba:abcd", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:ddde:9999:b342::324e:dcba:abcd", + "match": [ + { + "match": "a123:ddde:9999:b342::324e:dcba:abcd", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "1:2:3:4:5:6:7:8", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123:bce:ddde:9999:b342::324e:dcba:abcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "a123::9999:b342::324e:dcba:abcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "abcde:2:3:4:5:6:7:8", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "::1", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "abcd:fee0:123::", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": ":1", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?!:) # colon disallowed at start\n (?: # start of item\n (?: [0-9a-f]{1,4} | # 1-4 hex digits or\n (?(1)0 | () ) ) # if null previously matched, fail; else null\n : # followed by colon\n ){1,7} # end item; 1-7 of them required\n [0-9a-f]{1,4} $ # final hex number at end of string\n (?(1)|.) # check that there was an empty component\n /ix", + "haystack": "1:", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "z", + "match": [ + { + "match": "z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "-", + "match": [ + { + "match": "-" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "d", + "match": [ + { + "match": "d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "]", + "match": [ + { + "match": "]" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/[z\\Qa-d]\\E]/", + "haystack": "b", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(a+)*b/", + "haystack": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i)reg(?:ul(?:[aä]|ae)r|ex)/", + "haystack": "REGular", + "match": [ + { + "match": "REGular" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i)reg(?:ul(?:[aä]|ae)r|ex)/", + "haystack": "regulaer", + "match": [ + { + "match": "regulaer" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i)reg(?:ul(?:[aä]|ae)r|ex)/", + "haystack": "Regex", + "match": [ + { + "match": "Regex" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i)reg(?:ul(?:[aä]|ae)r|ex)/", + "haystack": "regulär", + "match": [ + { + "match": "regul\\xe4r" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/Åæåä[à-ÿÀ-ß]+/", + "haystack": "Åæåäà", + "match": [ + { + "match": "\\xc5\\xe6\\xe5\\xe4\\xe0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/Åæåä[à-ÿÀ-ß]+/", + "haystack": "Åæåäÿ", + "match": [ + { + "match": "\\xc5\\xe6\\xe5\\xe4\\xff" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/Åæåä[à-ÿÀ-ß]+/", + "haystack": "ÅæåäÀ", + "match": [ + { + "match": "\\xc5\\xe6\\xe5\\xe4\\xc0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/Åæåä[à-ÿÀ-ß]+/", + "haystack": "Åæåäß", + "match": [ + { + "match": "\\xc5\\xe6\\xe5\\xe4\\xdf" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=Z)X./", + "haystack": "\\x84XAZXB", + "match": [ + { + "match": "XB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ab cd (?x) de fg/", + "haystack": "ab cd defg", + "match": [ + { + "match": "ab cd defg" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ab cd(?x) de fg/", + "haystack": "ab cddefg", + "match": [ + { + "match": "ab cddefg" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/ab cd(?x) de fg/", + "haystack": "abcddefg", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?a|)*\\d/", + "haystack": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4", + "match": [ + { + "match": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>a|)*\\d/", + "haystack": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:a|)*\\d/", + "haystack": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4", + "match": [ + { + "match": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:a|)*\\d/", + "haystack": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\Z/g", + "haystack": "abc\\n", + "match": [ + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?s)(?>.*)(?.*)(?(a))b|(a)c/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(a))ab|(a)c/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>(a))b|(a)c)/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group1": "ac", + "group3": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>(a))b|(a)c)++/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group1": "ac", + "group3": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?>(a))b|(a)c)++/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(?>(a))b|(a)c)(..)/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "a", + "group3": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(?>(a))b|(a)c)/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?>([ab])))+a=/", + "haystack": "=ba=", + "match": [ + { + "match": "ba=", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>([ab]))+a=/", + "haystack": "=ba=", + "match": [ + { + "match": "ba=", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>(a+)b)+(aabab))/", + "haystack": "aaaabaaabaabab", + "match": [ + { + "match": "aaaabaaabaabab", + "group1": "aaaabaaabaabab", + "group2": "aaa", + "group3": "aabab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>a+|ab)+?c/", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(?>a+|ab)+c/", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:a+|ab)+c/", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?=(a))a)/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?=(a))a)(b)/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:a|ab)++c/", + "haystack": "aaaabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^(?>a|ab)++c/", + "haystack": "aaaabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a|ab)+c/", + "haystack": "aaaabc", + "match": [ + { + "match": "aaaabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=abc){3}abc/", + "haystack": "abcabcabc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=abc){3}abc/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=abc)+abc/", + "haystack": "abcabcabc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=abc)+abc/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=abc)++abc/", + "haystack": "abcabcabc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=abc)++abc/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=abc){0}xyz/", + "haystack": "xyz", + "match": [ + { + "match": "xyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=abc){1}xyz/", + "haystack": "xyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=(a))?./", + "haystack": "ab", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(a))?./", + "haystack": "bc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(a))??./", + "haystack": "ab", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(a))??./", + "haystack": "bc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?=(?1))?[az]([abc])d/", + "haystack": "abd", + "match": [ + { + "match": "abd", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?=(?1))?[az]([abc])d/", + "haystack": "zcdxx", + "match": [ + { + "match": "zcd", + "group1": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!a){0}\\w+/", + "haystack": "aaaaa", + "match": [ + { + "match": "aaaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(abc))?xyz/", + "haystack": "abcxyz", + "match": [ + { + "match": "xyz", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(abc))?xyz/", + "haystack": "pqrxyz", + "match": [ + { + "match": "xyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[\\g]+/", + "haystack": "ggg<<>>", + "match": [ + { + "match": "ggg<<>>" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[\\g]+/", + "haystack": "\\\\ga", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[\\ga]+/", + "haystack": "gggagagaxyz", + "match": [ + { + "match": "gggagaga" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[:a[:digit:]]+/", + "haystack": "aaaa444:::Z", + "match": [ + { + "match": "aaaa444:::" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^[:a[:digit:]:b]+/", + "haystack": "aaaa444:::bbbZ", + "match": [ + { + "match": "aaaa444:::bbb" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[:a]xxx[b:]/", + "haystack": ":xxx:", + "match": [ + { + "match": ":xxx:" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=a{2})b/i", + "haystack": "xaabc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=a{2})b/i", + "haystack": "xabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?XNNNYZ", + "match": [ + { + "match": "XNNNYZ" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\h*X\\h?\\H+Y\\H?Z/", + "haystack": "> X NYQZ", + "match": [ + { + "match": " X NYQZ" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\h*X\\h?\\H+Y\\H?Z/", + "haystack": ">XYZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\h*X\\h?\\H+Y\\H?Z/", + "haystack": "> X NY Z", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\v*X\\v?Y\\v+Z\\V*\\x0a\\V+\\x0b\\V{2,3}\\x0c/", + "haystack": ">XY\\x0aZ\\x0aA\\x0bNN\\x0c", + "match": [ + { + "match": "XY\\x0aZ\\x0aA\\x0bNN\\x0c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\v*X\\v?Y\\v+Z\\V*\\x0a\\V+\\x0b\\V{2,3}\\x0c/", + "haystack": ">\\x0a\\x0dX\\x0aY\\x0a\\x0bZZZ\\x0aAAA\\x0bNNN\\x0c", + "match": [ + { + "match": "\\x0a\\x0dX\\x0aY\\x0a\\x0bZZZ\\x0aAAA\\x0bNNN\\x0c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(foo)\\Kbar/", + "haystack": "foobar", + "match": [ + { + "match": "bar", + "group1": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(foo)(\\Kbar|baz)/", + "haystack": "foobar", + "match": [ + { + "match": "bar", + "group1": "foo", + "group2": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(foo)(\\Kbar|baz)/", + "haystack": "foobaz", + "match": [ + { + "match": "foobaz", + "group1": "foo", + "group2": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(foo\\Kbar)baz/", + "haystack": "foobarbaz", + "match": [ + { + "match": "barbaz", + "group1": "foobar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/abc\\K|def\\K/g", + "haystack": "Xabcdefghi", + "match": [ + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ab\\Kc|de\\Kf/g", + "haystack": "Xabcdefghi", + "match": [ + { + "match": "c" + }, + { + "match": "f" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=C)/g", + "haystack": "ABCDECBA", + "match": [ + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^abc\\K/", + "haystack": "abcdef", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^abc\\K/", + "haystack": "defabcxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a(b))\\1\\g1\\g{1}\\g-1\\g{-1}\\g{-2}Z/", + "haystack": "ababababbbabZXXXX", + "match": [ + { + "match": "ababababbbabZ", + "group1": "ab", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?tom|bon)-\\g{A}/", + "haystack": "tom-tom", + "match": [ + { + "match": "tom-tom", + "group1": "tom" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?tom|bon)-\\g{A}/", + "haystack": "bon-bon", + "match": [ + { + "match": "bon-bon", + "group1": "bon" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(^(a|b\\g{-1}))/", + "haystack": "bacxxx", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?|(abc)|(xyz))\\1/", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(abc)|(xyz))\\1/", + "haystack": "xyzxyz", + "match": [ + { + "match": "xyzxyz", + "group1": "xyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?|(abc)|(xyz))\\1/", + "haystack": "abcxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?|(abc)|(xyz))\\1/", + "haystack": "xyzabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?|(abc)|(xyz))(?1)/", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(abc)|(xyz))(?1)/", + "haystack": "xyzabc", + "match": [ + { + "match": "xyzabc", + "group1": "xyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?|(abc)|(xyz))(?1)/", + "haystack": "xyzxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^X(?5)(a)(?|(b)|(q))(c)(d)(Y)/", + "haystack": "XYabcdY", + "match": [ + { + "match": "XYabcdY", + "group1": "a", + "group2": "b", + "group3": "c", + "group4": "d", + "group5": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^X(?7)(a)(?|(b|(r)(s))|(q))(c)(d)(Y)/", + "haystack": "XYabcdY", + "match": [ + { + "match": "XYabcdY", + "group1": "a", + "group2": "b", + "group5": "c", + "group6": "d", + "group7": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^X(?7)(a)(?|(b|(?|(r)|(t))(s))|(q))(c)(d)(Y)/", + "haystack": "XYabcdY", + "match": [ + { + "match": "XYabcdY", + "group1": "a", + "group2": "b", + "group5": "c", + "group6": "d", + "group7": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\k{2}/", + "haystack": "a:aaxyz", + "match": [ + { + "match": "a:aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\k{2}/", + "haystack": "ab:ababxyz", + "match": [ + { + "match": "ab:abab", + "group1": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?'abc'\\w+):\\k{2}/", + "haystack": "a:axyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\k{2}/", + "haystack": "ab:abxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\g{abc}{2}/", + "haystack": "a:aaxyz", + "match": [ + { + "match": "a:aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\g{abc}{2}/", + "haystack": "ab:ababxyz", + "match": [ + { + "match": "ab:abab", + "group1": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?'abc'\\w+):\\g{abc}{2}/", + "haystack": "a:axyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?'abc'\\w+):\\g{abc}{2}/", + "haystack": "ab:abxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?a)? (?()b|c) (?('ab')d|e)/x", + "haystack": "abd", + "match": [ + { + "match": "abd", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?a)? (?()b|c) (?('ab')d|e)/x", + "haystack": "ce", + "match": [ + { + "match": "ce" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a.)\\g-1Z/", + "haystack": "aXaXZ", + "match": [ + { + "match": "aXaXZ", + "group1": "aX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a.)\\g{-1}Z/", + "haystack": "aXaXZ", + "match": [ + { + "match": "aXaXZ", + "group1": "aX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(DEFINE) (? a) (? b) ) (?&A) (?&B) /x", + "haystack": "abcd", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?:(?:a(?&all))|(b))(c?))/", + "haystack": "aabc", + "match": [ + { + "match": "aabc", + "group1": "aabc", + "group3": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(b)|(c))(?1)/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "ab", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(b)|(c))(?1)/", + "haystack": "cab", + "match": [ + { + "match": "cab", + "group1": "c", + "group3": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(a(b)|(c))/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "c", + "group3": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(a(b)|(c))/", + "haystack": "cab", + "match": [ + { + "match": "cab", + "group1": "ab", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?&NAME_PAT))\\s+(?(?&ADDRESS_PAT))\n (?(DEFINE)\n (?[a-z]+)\n (?\\d+)\n )/x", + "haystack": "metcalfe 33", + "match": [ + { + "match": "metcalfe 33", + "group1": "metcalfe", + "group2": "33" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))\\b(?&byte)(\\.(?&byte)){3}/", + "haystack": "1.2.3.4", + "match": [ + { + "match": "1.2.3.4", + "group2": ".4" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))\\b(?&byte)(\\.(?&byte)){3}/", + "haystack": "131.111.10.206", + "match": [ + { + "match": "131.111.10.206", + "group2": ".206" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))\\b(?&byte)(\\.(?&byte)){3}/", + "haystack": "10.0.0.0", + "match": [ + { + "match": "10.0.0.0", + "group2": ".0" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))\\b(?&byte)(\\.(?&byte)){3}/", + "haystack": "10.6", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))\\b(?&byte)(\\.(?&byte)){3}/", + "haystack": "455.3.4.5", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\b(?&byte)(\\.(?&byte)){3}(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))/", + "haystack": "1.2.3.4", + "match": [ + { + "match": "1.2.3.4", + "group1": ".4" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\b(?&byte)(\\.(?&byte)){3}(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))/", + "haystack": "131.111.10.206", + "match": [ + { + "match": "131.111.10.206", + "group1": ".206" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\b(?&byte)(\\.(?&byte)){3}(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))/", + "haystack": "10.0.0.0", + "match": [ + { + "match": "10.0.0.0", + "group1": ".0" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\b(?&byte)(\\.(?&byte)){3}(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))/", + "haystack": "10.6", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\b(?&byte)(\\.(?&byte)){3}(?(DEFINE)(?2[0-4]\\d|25[0-5]|1\\d\\d|[1-9]?\\d))/", + "haystack": "455.3.4.5", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(\\w++|\\s++)*$/", + "haystack": "now is the time for all good men to come to the aid of the party", + "match": [ + { + "match": "now is the time for all good men to come to the aid of the party", + "group1": "party" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(\\w++|\\s++)*$/", + "haystack": "this is not a line with only words and spaces!", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(\\d++)(\\w)/", + "haystack": "12345a", + "match": [ + { + "match": "12345a", + "group1": "12345", + "group2": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(\\d++)(\\w)/", + "haystack": "12345+", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a++b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a++b)/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a++)b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/([^()]++|\\([^()]*\\))+/", + "haystack": "((abc(ade)ufh()()x", + "match": [ + { + "match": "abc(ade)ufh()()x", + "group1": "x" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\(([^()]++|\\([^()]+\\))+\\)/", + "haystack": "(abc)", + "match": [ + { + "match": "(abc)", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\(([^()]++|\\([^()]+\\))+\\)/", + "haystack": "(abc(def)xyz)", + "match": [ + { + "match": "(abc(def)xyz)", + "group1": "xyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/\\(([^()]++|\\([^()]+\\))+\\)/", + "haystack": "((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "a(b)c", + "match": [ + { + "match": "a(b)c", + "group1": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "a(b(c))d", + "match": [ + { + "match": "a(b(c))d", + "group1": "d" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "a(b(c)d", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^>abc>([^()]|\\((?1)*\\))*abc>123abc>123abc>([^()]|\\((?1)*\\))*abc>1(2)3abc>1(2)3abc>([^()]|\\((?1)*\\))*abc>(1(2)3)abc>(1(2)3)]*+) | (?2)) * >))/x", + "haystack": "<>", + "match": [ + { + "match": "<>", + "group1": "<>", + "group2": "<>" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": "", + "match": [ + { + "match": "", + "group1": "", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": " hij>", + "match": [ + { + "match": " hij>", + "group1": " hij>", + "group2": " hij>" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": " hij>", + "match": [ + { + "match": "", + "group1": "", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": "def>", + "match": [ + { + "match": "def>", + "group1": "def>", + "group2": "def>" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": "", + "match": [ + { + "match": "<>", + "group1": "<>", + "group2": "<>" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/((< (?: (?(R) \\d++ | [^<>]*+) | (?2)) * >))/x", + "haystack": "a)(?<=b(?&X))/", + "haystack": "baz", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))\\1/", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))\\1/", + "haystack": "defdef", + "match": [ + { + "match": "defdef", + "group1": "def" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?|(abc)|(def))\\1/", + "haystack": "abcdef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))\\1/", + "haystack": "defabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))(?1)/", + "haystack": "abcabc", + "match": [ + { + "match": "abcabc", + "group1": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))(?1)/", + "haystack": "defabc", + "match": [ + { + "match": "defabc", + "group1": "def" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?|(abc)|(def))(?1)/", + "haystack": "defdef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?|(abc)|(def))(?1)/", + "haystack": "abcdef", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:a(? (?')|(?\")) |b(? (?')|(?\")) ) (?('quote')[a-z]+|[0-9]+)/x", + "haystack": "a\\\"aaaaa", + "match": [ + { + "match": "a\"aaaaa", + "group1": "\"", + "group3": "\"" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:a(? (?')|(?\")) |b(? (?')|(?\")) ) (?('quote')[a-z]+|[0-9]+)/x", + "haystack": "b\\\"aaaaa", + "match": [ + { + "match": "b\"aaaaa", + "group4": "\"", + "group6": "\"" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:a(? (?')|(?\")) |b(? (?')|(?\")) ) (?('quote')[a-z]+|[0-9]+)/x", + "haystack": "b\\\"11111", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*F)|C)/", + "haystack": "ABCD", + "match": [ + { + "match": "BC", + "group1": "C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*F)|C)/", + "haystack": "CCD", + "match": [ + { + "match": "CC", + "group1": "C" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:(?1)|B)(A(*F)|C)/", + "haystack": "CAD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:(?1)|B)(A(*F)|C)/", + "haystack": "CCD", + "match": [ + { + "match": "CC", + "group1": "C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:(?1)|B)(A(*F)|C)/", + "haystack": "BCD", + "match": [ + { + "match": "BC", + "group1": "C" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:(?1)|B)(A(*F)|C)/", + "haystack": "ABCD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:(?1)|B)(A(*F)|C)/", + "haystack": "CAD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:(?1)|B)(A(*F)|C)/", + "haystack": "BAD", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "AAD", + "match": [ + { + "match": "AA", + "group1": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "ACD", + "match": [ + { + "match": "ACD", + "group1": "C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "BAD", + "match": [ + { + "match": "BA", + "group1": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "BCD", + "match": [ + { + "match": "BCD", + "group1": "C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "BAX", + "match": [ + { + "match": "BA", + "group1": "A" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "ACX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?1)|B)(A(*ACCEPT)XX|C)D/", + "haystack": "ABC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(A))B(?1)C/", + "haystack": "BAC", + "match": [ + { + "match": "BAC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)((A)\\2))B(?1)C/", + "haystack": "BAAC", + "match": [ + { + "match": "BAAC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(? \\( ( [^()]++ | (?&pn) )* \\) )/x", + "haystack": "(ab(cd)ef)", + "match": [ + { + "match": "(ab(cd)ef)", + "group1": "(ab(cd)ef)", + "group2": "ef" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?=a(*SKIP)b|ac)/", + "haystack": "ac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?=a(*PRUNE)b)/", + "haystack": "ab", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?=a(*PRUNE)b)/", + "haystack": "ac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?=a(*ACCEPT)b)/", + "haystack": "ac", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a\\Kb)/", + "haystack": "ab", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?>a\\Kb))/", + "haystack": "ab", + "match": [ + { + "match": "b", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a\\Kb)/", + "haystack": "ab", + "match": [ + { + "match": "b", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^a\\Kcz|ac/", + "haystack": "ac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a\\Kbz|ab)/", + "haystack": "ab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?&t)(?(DEFINE)(?a\\Kb))$/", + "haystack": "ab", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "a(b)c", + "match": [ + { + "match": "a(b)c", + "group1": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^([^()]|\\((?1)*\\))*$/", + "haystack": "a(b(c)d)e", + "match": [ + { + "match": "a(b(c)d)e", + "group1": "e" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)(?P>L1)|(?P>L2))/", + "haystack": "0", + "match": [ + { + "match": "0", + "group1": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)(?P>L1)|(?P>L2))/", + "haystack": "00", + "match": [ + { + "match": "00", + "group1": "00", + "group2": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)(?P>L1)|(?P>L2))/", + "haystack": "0000", + "match": [ + { + "match": "0000", + "group1": "0000", + "group2": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)|(?P>L2)(?P>L1))/", + "haystack": "0", + "match": [ + { + "match": "0", + "group1": "0", + "group2": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)|(?P>L2)(?P>L1))/", + "haystack": "00", + "match": [ + { + "match": "0", + "group1": "0", + "group2": "0" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P0)|(?P>L2)(?P>L1))/", + "haystack": "0000", + "match": [ + { + "match": "0", + "group1": "0", + "group2": "0" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/A(*COMMIT)(B|D)/", + "haystack": "ACABX", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^(A(*PRUNE:A)B|C(*PRUNE:B)D)/", + "haystack": "AC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(A(*PRUNE:A)B|C(*PRUNE:B)D)/", + "haystack": "CB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*MARK:A)(*SKIP:B)(C|X)/", + "haystack": "C", + "match": [ + { + "match": "C", + "group1": "C" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*MARK:A)(*SKIP:B)(C|X)/", + "haystack": "D", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^(A(*THEN:A)B|C(*THEN:B)D)/", + "haystack": "CB", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^(?:A(*THEN:A)B|C(*THEN:B)D)/", + "haystack": "CB", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^(?>A(*THEN:A)B|C(*THEN:B)D)/", + "haystack": "CB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/A(*MARK:A)A+(*SKIP:A)(B|Z) | AC/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A(*MARK:A)A+(*MARK:B)(*SKIP:A)(B|Z) | AC/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A(*:A)A+(*SKIP:A)(B|Z) | AC/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*:A)A+(*SKIP:A)(B|Z)/", + "haystack": "AAAC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC(*:B)/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*COMMIT)(A|P)(B|P)(C|P)/", + "haystack": "ABCDEFG", + "match": [ + { + "match": "ABC", + "group1": "A", + "group2": "B", + "group3": "C" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*COMMIT)(A|P)(B|P)(C|P)/", + "haystack": "DEFGABC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(\\w+)(?>b(*COMMIT))\\w{2}/", + "haystack": "abbb", + "match": [ + { + "match": "abbb", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(\\w+)b(*COMMIT)\\w{2}/", + "haystack": "abbb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?&t)(?#()(?(DEFINE)(?a))/", + "haystack": "bac", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>(*COMMIT)(?>yes|no)(*THEN)(*F))?/", + "haystack": "yes", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(?>(*COMMIT)(yes|no)(*THEN)(*F))?/", + "haystack": "yes", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/b?(*SKIP)c/", + "haystack": "bc", + "match": [ + { + "match": "bc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/b?(*SKIP)c/", + "haystack": "abc", + "match": [ + { + "match": "bc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*SKIP)bc/", + "haystack": "a", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(*SKIP)b/", + "haystack": "a", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?P(?P=abn)xxx|)+/", + "haystack": "xxx", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "aa", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "aA", + "match": [ + { + "match": "aA", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "aB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "Ba", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i:([^b]))(?1)/", + "haystack": "ba", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?&t)*+(?(DEFINE)(?a))\\w$/", + "haystack": "aaaaaaX", + "match": [ + { + "match": "aaaaaaX" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?&t)*+(?(DEFINE)(?a))\\w$/", + "haystack": "aaaaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?&t)*(?(DEFINE)(?a))\\w$/", + "haystack": "aaaaaaX", + "match": [ + { + "match": "aaaaaaX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?&t)*(?(DEFINE)(?a))\\w$/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)*+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "a", + "group2": "X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)*+(\\w)/", + "haystack": "YZ", + "match": [ + { + "match": "Y", + "group2": "Y" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a)*+(\\w)/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)*+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)*+(\\w)/", + "haystack": "YZ", + "match": [ + { + "match": "Y", + "group1": "Y" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:a)*+(\\w)/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a)++(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "a", + "group2": "X" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a)++(\\w)/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a)++(\\w)/", + "haystack": "YZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)++(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "X" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:a)++(\\w)/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)++(\\w)/", + "haystack": "YZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a)?+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aa", + "group1": "a", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)?+(\\w)/", + "haystack": "YZ", + "match": [ + { + "match": "Y", + "group2": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)?+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:a)?+(\\w)/", + "haystack": "YZ", + "match": [ + { + "match": "Y", + "group1": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a){2,}+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "a", + "group2": "X" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a){2,}+(\\w)/", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(a){2,}+(\\w)/", + "haystack": "YZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a){2,}+(\\w)/", + "haystack": "aaaaX", + "match": [ + { + "match": "aaaaX", + "group1": "X" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:a){2,}+(\\w)/", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?:a){2,}+(\\w)/", + "haystack": "YZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a|)*(?1)b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a|)*(?1)b/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a|)*(?1)b/", + "haystack": "aab", + "match": [ + { + "match": "aab", + "group1": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a)++(?1)b/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a)++(?1)b/", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(a)*+(?1)b/", + "haystack": "ab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a)*+(?1)b/", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?1)(?:(b)){0}/", + "haystack": "b", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(foo ( \\( ((?:(?> [^()]+ )|(?2))*) \\) ) )/x", + "haystack": "foo(bar(baz)+baz(bop))", + "match": [ + { + "match": "foo(bar(baz)+baz(bop))", + "group1": "foo(bar(baz)+baz(bop))", + "group2": "(bar(baz)+baz(bop))", + "group3": "bar(baz)+baz(bop)" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(A (A|B(*ACCEPT)|C) D)(E)/x", + "haystack": "AB", + "match": [ + { + "match": "AB", + "group1": "AB", + "group2": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A.*?(a|bc)/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A.*?(?:a|bc)++/", + "haystack": "ba", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A.*?(a|bc)++/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A.*?(?:a|bc|d)/", + "haystack": "ba", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(b))++/", + "haystack": "beetle", + "match": [ + { + "match": "b", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?=(a(*ACCEPT)z))a)/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a)(?1)+ab/", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a)(?1)++ab/", + "haystack": "aaaab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?=a(*:M))aZ/", + "haystack": "aZbc", + "match": [ + { + "match": "aZ" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!(*:M)b)aZ/", + "haystack": "aZbc", + "match": [ + { + "match": "aZ" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(a))?b(?1)/", + "haystack": "backgammon", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\N+/", + "haystack": "abc\\ndef", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\N{1,}/", + "haystack": "abc\\ndef", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(R)a+|(?R)b)/", + "haystack": "aaaabcde", + "match": [ + { + "match": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(R)a+|((?R))b)/", + "haystack": "aaaabcde", + "match": [ + { + "match": "aaaab", + "group1": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(R)a+|(?1)b))/", + "haystack": "aaaabcde", + "match": [ + { + "match": "aaaab", + "group1": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(R1)a+|(?1)b))/", + "haystack": "aaaabcde", + "match": [ + { + "match": "aaaab", + "group1": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(R)a|(?1)))*/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(R)a|(?1)))+/", + "haystack": "aaa", + "match": [ + { + "match": "aaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(*:any\nname)/", + "haystack": "abc", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(?&t)c|(?&t))(?(DEFINE)(?a|b(*PRUNE)c))/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(?&t)c|(?&t))(?(DEFINE)(?a|b(*PRUNE)c))/", + "haystack": "ba", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(?&t)c|(?&t))(?(DEFINE)(?a|b(*PRUNE)c))/", + "haystack": "bba", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? (a(*THEN)b) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*? (a(*THEN)b|(*F)) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*? ( (a(*THEN)b) | (*F) ) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc", + "group1": "ab", + "group2": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? ( (a(*THEN)b) ) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?:a(*THEN)b) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?:a(*THEN)b|(*F)) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?: (?:a(*THEN)b) | (*F) ) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?: (?:a(*THEN)b) ) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?>a(*THEN)b) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?>a(*THEN)b|(*F)) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?> (?>a(*THEN)b) | (*F) ) c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?> (?>a(*THEN)b) ) c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^.*? (a(*THEN)b)++ c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*? (a(*THEN)b|(*F))++ c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*? ( (a(*THEN)b)++ | (*F) )++ c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc", + "group1": "ab", + "group2": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? ( (a(*THEN)b)++ )++ c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?:a(*THEN)b)++ c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?:a(*THEN)b|(*F))++ c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^.*? (?: (?:a(*THEN)b)++ | (*F) )++ c/x", + "haystack": "aabc", + "match": [ + { + "match": "aabc" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*? (?: (?:a(*THEN)b)++ )++ c/x", + "haystack": "aabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=a(*THEN)b)ab|ac)/", + "haystack": "ac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*?(?(?=a)a|b(*THEN)c)/", + "haystack": "ba", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*?(?:(?(?=a)a|b(*THEN)c)|d)/", + "haystack": "ba", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^.*?(?(?=a)a(*THEN)b|c)/", + "haystack": "ac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^.*(?=a(*THEN)b)/", + "haystack": "aabc", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(*:m))/imsx", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>(a)(*:m))/imsx", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(*ACCEPT)b)c/", + "haystack": "xacd", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(a(*COMMIT)b))c/", + "haystack": "xabcd", + "match": [ + { + "match": "c", + "group1": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=(a(*COMMIT)b))c/", + "haystack": "xacd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?a?)*)*c/", + "haystack": "aac", + "match": [ + { + "match": "aac", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?a)(?<=ba)/", + "haystack": "aba", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:.*?a)(?<=ba)/", + "haystack": "aba", + "match": [ + { + "match": "aba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?a)b/s", + "haystack": "aab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?a)b/", + "haystack": "aab", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>^a)b/s", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?)(?<=(abcd)|(wxyz))/", + "haystack": "alphabetabcd", + "match": [ + { + "match": "", + "group1": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?)(?<=(abcd)|(wxyz))/", + "haystack": "endingwxyz", + "match": [ + { + "match": "", + "group2": "wxyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*)(?<=(abcd)|(wxyz))/", + "haystack": "alphabetabcd", + "match": [ + { + "match": "alphabetabcd", + "group1": "abcd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>.*)(?<=(abcd)|(wxyz))/", + "haystack": "endingwxyz", + "match": [ + { + "match": "endingwxyz", + "group2": "wxyz" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>.*)foo/", + "haystack": "abcdfooxyz", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>.*?)foo/", + "haystack": "abcdfooxyz", + "match": [ + { + "match": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(a(*PRUNE)b)){0}(?:(?1)|ac)/", + "haystack": "ac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(a(*SKIP)b)){0}(?:(?1)|ac)/", + "haystack": "ac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?<=(*SKIP)ac)a/", + "haystack": "aa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/A(*MARK:A)A+(*SKIP:B)(B|Z) | AC/x", + "haystack": "AAAC", + "match": [ + { + "match": "AC" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(*SKIP:m)x|ac(*:n)(*SKIP:n)d|ac/", + "haystack": "acacd", + "match": [ + { + "match": "acd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A(*SKIP:m)x|A(*SKIP:n)x|AB/", + "haystack": "AB", + "match": [ + { + "match": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((*SKIP:r)d){0}a(*SKIP:m)x|ac(*:n)|ac/", + "haystack": "acacd", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*PRUNE)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*SKIP)(*PRUNE)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*SKIP:N)(*PRUNE)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaa(*:N)a(*SKIP:N)(*PRUNE)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*THEN)(*PRUNE)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*SKIP)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*PRUNE)(*SKIP)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*THEN)(*SKIP)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*COMMIT)(*SKIP)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/aaaaa(*COMMIT)b|a+c/", + "haystack": "aaaaaac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*THEN)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*SKIP)(*THEN)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*PRUNE)(*THEN)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*COMMIT)(*THEN)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "aaaaaac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*:m)(*PRUNE:m)(*SKIP:m)m|a+/", + "haystack": "aaaaaa", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*:m)(*MARK:m)(*PRUNE)(*SKIP:m)m|a+/", + "haystack": "aaaaaa", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*:n)(*PRUNE:m)(*SKIP:m)m|a+/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaaaa(*:n)(*MARK:m)(*PRUNE)(*SKIP:m)m|a+/", + "haystack": "aaaaaa", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(*MARK:A)aa(*PRUNE:A)a(*SKIP:A)b|a+c/", + "haystack": "aaaac", + "match": [ + { + "match": "aac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(*MARK:A)aa(*MARK:A)a(*SKIP:A)b|a+c/", + "haystack": "aaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaa(*PRUNE:A)a(*SKIP:A)b|a+c/", + "haystack": "aaaac", + "match": [ + { + "match": "aac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/aaa(*MARK:A)a(*SKIP:A)b|a+c/", + "haystack": "aaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(*:m)a(*COMMIT)(*SKIP:m)b|a+c/", + "haystack": "aaaaaac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/.?(a|b(*THEN)c)/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a(*COMMIT)b)c|abd/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(a(*COMMIT)b)c|abd/", + "haystack": "abd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=a(*COMMIT)b)abc|abd/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=a(*COMMIT)b)abc|abd/", + "haystack": "abd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(*COMMIT)b)c|abd/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(*COMMIT)b)c|abd/", + "haystack": "abd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?=b(*COMMIT)c)[^d]|abd/", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?=b(*COMMIT)c)[^d]|abd/", + "haystack": "abd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?=bc).|abd/", + "haystack": "abd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?=bc).|abd/", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a(?>b(*COMMIT)c)d|abd/", + "haystack": "abceabd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a(?>bc)d|abd/", + "haystack": "abceabd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a(*COMMIT)b)c|abd/", + "haystack": "abd", + "match": [ + { + "match": "abd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?>a(*COMMIT)c)d|abd/", + "haystack": "abd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/((?=a(*COMMIT)b)ab|ac){0}(?:(?1)|a(c))/", + "haystack": "ac", + "match": [ + { + "match": "ac", + "group2": "c" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(a)?(?(1)a|b)+$/", + "haystack": "a", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/A(*PRUNE:A)A+(*SKIP:A)(B|Z) | AC/x", + "haystack": "AAAC", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^((abc|abcx)(*THEN)y|abcd)/", + "haystack": "abcd", + "match": [ + { + "match": "abcd", + "group1": "abcd" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^((abc|abcx)(*THEN)y|abcd)/", + "haystack": "abcxy", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/^((yes|no)(*THEN)(*F))?/", + "haystack": "yes", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C? (*THEN) | A D) (*FAIL)/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C? (*THEN) | A D) z/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C? (*THEN) | A D) \\s* (*FAIL)/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C? (*THEN) | A D) \\s* z/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (?:C|) (*THEN) | A D) (*FAIL)/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (?:C|) (*THEN) | A D) z/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C{0,6} (*THEN) | A D) (*FAIL)/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) C{0,6} (*THEN) | A D) z/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (CE){0,6} (*THEN) | A D) (*FAIL)/x", + "haystack": "AbcdCEBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (CE){0,6} (*THEN) | A D) z/x", + "haystack": "AbcdCEBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (CE*){0,6} (*THEN) | A D) (*FAIL)/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(A (.*) (CE*){0,6} (*THEN) | A D) z/x", + "haystack": "AbcdCBefgBhiBqz", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(?=a(*COMMIT)b|ac)ac|ac/", + "haystack": "ac", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(?=a(*COMMIT)b|(ac)) ac | (a)c/x", + "haystack": "ac", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(?!b(*THEN)a)bn|bnn)/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!b(*SKIP)a)bn|bnn/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?!b(*SKIP)a)bn|bnn)/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!b(*PRUNE)a)bn|bnn/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?!b(*PRUNE)a)bn|bnn)/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!b(*COMMIT)a)bn|bnn/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?!b(*COMMIT)a)bn|bnn)/", + "haystack": "bnn", + "match": [ + { + "match": "bn" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?=b(*SKIP)a)bn|bnn/", + "haystack": "bnn", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=b(*THEN)a)bn|bnn/", + "haystack": "bnn", + "match": [ + { + "match": "bnn" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!a(*SKIP)b)/", + "haystack": "ac", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!a(*SKIP)b)../", + "haystack": "acd", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!a(*SKIP)b)../", + "haystack": "acd", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!a(*SKIP)b))/", + "haystack": "ac", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?!a(*PRUNE)b)../", + "haystack": "acd", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!a(*PRUNE)b)../", + "haystack": "acd", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!a(*COMMIT)b)ac|cd/", + "haystack": "ac", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A.*?(?:a|bc)/", + "haystack": "ba", + "match": [ + { + "match": "ba" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(A(*THEN)B|C(*THEN)D)/", + "haystack": "CD", + "match": [ + { + "match": "CD", + "group1": "CD" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*:m(m)(?&y)(?(DEFINE)(?b))/", + "haystack": "abc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*PRUNE:m(m)(?&y)(?(DEFINE)(?b))/", + "haystack": "abc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*SKIP:m(m)(?&y)(?(DEFINE)(?b))/", + "haystack": "abc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*THEN:m(m)(?&y)(?(DEFINE)(?b))/", + "haystack": "abc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\d*\\w{4}/", + "haystack": "1234", + "match": [ + { + "match": "1234" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^\\d*\\w{4}/", + "haystack": "123", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^b]*\\w{4}/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[^b]*\\w{4}/", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^[^b]*\\w{4}/i", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^[^b]*\\w{4}/i", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w{4}/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^a*\\w{4}/", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^a*\\w{4}/i", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^a*\\w{4}/i", + "haystack": "aaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:(?foo)|(?bar))\\k/", + "haystack": "foofoo", + "match": [ + { + "match": "foofoo", + "group1": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:(?foo)|(?bar))\\k/", + "haystack": "barbar", + "match": [ + { + "match": "barbar", + "group2": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?A)(?:(?foo)|(?bar))\\k/", + "haystack": "AfooA", + "match": [ + { + "match": "AfooA", + "group1": "A", + "group2": "foo" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?A)(?:(?foo)|(?bar))\\k/", + "haystack": "AbarA", + "match": [ + { + "match": "AbarA", + "group1": "A", + "group3": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?A)(?:(?foo)|(?bar))\\k/", + "haystack": "Afoofoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?A)(?:(?foo)|(?bar))\\k/", + "haystack": "Abarbar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(\\d+)\\s+IN\\s+SOA\\s+(\\S+)\\s+(\\S+)\\s*\\(\\s*$/", + "haystack": "1 IN SOA non-sp1 non-sp2(", + "match": [ + { + "match": "1 IN SOA non-sp1 non-sp2(", + "group1": "1", + "group2": "non-sp1", + "group3": "non-sp2" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^ (?:(?A)|(?'B'B)(?A)) (?('A')x) (?()y)$/x", + "haystack": "Ax", + "match": [ + { + "match": "Ax", + "group1": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^ (?:(?A)|(?'B'B)(?A)) (?('A')x) (?()y)$/x", + "haystack": "BAxy", + "match": [ + { + "match": "BAxy", + "group2": "B", + "group3": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^A\\xZ/", + "haystack": "A\\0Z", + "match": [ + { + "match": "A\\x00Z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^A\\o{123}B/", + "haystack": "A\\123B", + "match": [ + { + "match": "ASB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ ^ a + + b $ /x", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ ^ a + #comment\n + b $ /x", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ ^ a + #comment\n #comment\n + b $ /x", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ ^ (?> a + ) b $ /x", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/ ^ ( a + ) + + \\w $ /x", + "haystack": "aaaab", + "match": [ + { + "match": "aaaab", + "group1": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:a\\Kb)*+/", + "haystack": "ababc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>a\\Kb)*/", + "haystack": "ababc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:a\\Kb)*/", + "haystack": "ababc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a\\Kb)*+/", + "haystack": "ababc", + "match": [ + { + "match": "b", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a\\Kb)*/", + "haystack": "ababc", + "match": [ + { + "match": "b", + "group1": "ab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:x|(?:(xx|yy)+|x|x|x|x|x)|a|a|a)bc/", + "haystack": "acb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/\\A(?:[^\\\"]++|\\\"(?:[^\\\"]*+|\\\"\\\")*+\\\")++/", + "haystack": "NON QUOTED \\\"QUOT\\\"\\\"ED\\\" AFTER \\\"NOT MATCHED", + "match": [ + { + "match": "NON QUOTED \"QUOT\"\"ED\" AFTER " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A(?:[^\\\"]++|\\\"(?:[^\\\"]++|\\\"\\\")*+\\\")++/", + "haystack": "NON QUOTED \\\"QUOT\\\"\\\"ED\\\" AFTER \\\"NOT MATCHED", + "match": [ + { + "match": "NON QUOTED \"QUOT\"\"ED\" AFTER " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A(?:[^\\\"]++|\\\"(?:[^\\\"]++|\\\"\\\")++\\\")++/", + "haystack": "NON QUOTED \\\"QUOT\\\"\\\"ED\\\" AFTER \\\"NOT MATCHED", + "match": [ + { + "match": "NON QUOTED \"QUOT\"\"ED\" AFTER " + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\A([^\\\"1]++|[\\\"2]([^\\\"3]*+|[\\\"4][\\\"5])*+[\\\"6])++/", + "haystack": "NON QUOTED \\\"QUOT\\\"\\\"ED\\\" AFTER \\\"NOT MATCHED", + "match": [ + { + "match": "NON QUOTED \"QUOT\"\"ED\" AFTER ", + "group1": " AFTER ", + "group2": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^\\w+(?>\\s*)(?<=\\w)/", + "haystack": "test test", + "match": [ + { + "match": "tes" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)(?Pb)/g", + "haystack": "abbaba", + "match": [ + { + "match": "ab", + "group1": "a", + "group2": "b" + }, + { + "match": "ab", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)(?Pb)(?P=same)/g", + "haystack": "abbaba", + "match": [ + { + "match": "aba", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?P=same)?(?Pa)(?Pb)/g", + "haystack": "abbaba", + "match": [ + { + "match": "ab", + "group1": "a", + "group2": "b" + }, + { + "match": "ab", + "group1": "a", + "group2": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:(?P=same)?(?:(?P=same)(?Pa)(?P=same)|(?P=same)?(?Pb)(?P=same)){2}(?P=same)(?Pc)(?P=same)){2}(?Pz)?/g", + "haystack": "bbbaaaccccaaabbbcc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)?(?Pb)?(?()c|d)*l/", + "haystack": "acl", + "match": [ + { + "match": "acl", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)?(?Pb)?(?()c|d)*l/", + "haystack": "bdl", + "match": [ + { + "match": "bdl", + "group2": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)?(?Pb)?(?()c|d)*l/", + "haystack": "adl", + "match": [ + { + "match": "dl" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?Pa)?(?Pb)?(?()c|d)*l/", + "haystack": "bcl", + "match": [ + { + "match": "l" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/\\sabc/", + "haystack": "\\x{0b}abc", + "match": [ + { + "match": "\\x0babc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\Qa]\\E]+/", + "haystack": "aa]]", + "match": [ + { + "match": "aa]]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[\\Q]a\\E]+/", + "haystack": "aa]]", + "match": [ + { + "match": "aa]]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A((((((((a))))))))\\8B/", + "haystack": "AaaB", + "match": [ + { + "match": "AaaB", + "group1": "a", + "group2": "a", + "group3": "a", + "group4": "a", + "group5": "a", + "group6": "a", + "group7": "a", + "group8": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A(((((((((a)))))))))\\9B/", + "haystack": "AaaB", + "match": [ + { + "match": "AaaB", + "group1": "a", + "group2": "a", + "group3": "a", + "group4": "a", + "group5": "a", + "group6": "a", + "group7": "a", + "group8": "a", + "group9": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A[\\8\\9]B/", + "haystack": "A8B", + "match": [ + { + "match": "A8B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A[\\8\\9]B/", + "haystack": "A9B", + "match": [ + { + "match": "A9B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(|ab)*?d/", + "haystack": "abd", + "match": [ + { + "match": "abd", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(|ab)*?d/", + "haystack": "xyd", + "match": [ + { + "match": "d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:((abcd))|(((?:(?:(?:(?:abc|(?:abcdef))))b)abcdefghi)abc)|((*ACCEPT)))/", + "haystack": "1234abcd", + "match": [ + { + "match": "", + "group5": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(\\2|a)(\\1)/", + "haystack": "aaa", + "match": [ + { + "match": "aa", + "group1": "a", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(?#?'){8}(a)/", + "haystack": "baaaaaaaaac", + "match": [ + { + "match": "aaaaaaaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((((((((((((x))))))))))))\\12/", + "haystack": "xx", + "match": [ + { + "match": "xx", + "group1": "x", + "group2": "x", + "group3": "x", + "group4": "x", + "group5": "x", + "group6": "x", + "group7": "x", + "group8": "x", + "group9": "x", + "group10": "x", + "group11": "x", + "group12": "x" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A[\\8]B[\\9]C/", + "haystack": "A8B9C", + "match": [ + { + "match": "A8B9C" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)()((((((\\1++))\\x85)+)|))/", + "haystack": "\\x85\\x85", + "match": [ + { + "match": "\\x85\\x85", + "group1": "", + "group2": "\\x85\\x85", + "group3": "\\x85\\x85", + "group4": "\\x85\\x85", + "group5": "\\x85", + "group6": "", + "group7": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(\\k'Pm')|(?'Pm'))/", + "haystack": "abcd", + "match": [ + { + "match": "", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))\\g{1}/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaaaa", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))\\g{1}/", + "haystack": "bb", + "match": [ + { + "match": "bb", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))(?1)/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaaaa", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))(?1)/", + "haystack": "baaa", + "match": [ + { + "match": "baaa", + "group1": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?|(aaa)|(b))(?1)/", + "haystack": "bb", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))/", + "haystack": "xaaa", + "match": [ + { + "match": "aaa", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(aaa)|(b))/", + "haystack": "xbc", + "match": [ + { + "match": "b", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(?'a'aaa)|(?'a'b))\\k'a'/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaaaa", + "group1": "aaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(?'a'aaa)|(?'a'b))\\k'a'/", + "haystack": "bb", + "match": [ + { + "match": "bb", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(?'a'aaa)|(?'a'b))(?'a'cccc)\\k'a'/", + "haystack": "aaaccccaaa", + "match": [ + { + "match": "aaaccccaaa", + "group1": "aaa", + "group2": "cccc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?|(?'a'aaa)|(?'a'b))(?'a'cccc)\\k'a'/", + "haystack": "bccccb", + "match": [ + { + "match": "bccccb", + "group1": "b", + "group2": "cccc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/x (*MARK:ab cd # comment\nef) x/x", + "haystack": "axxz", + "match": [ + { + "match": "xx" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(B){0}c)X/", + "haystack": "acX", + "match": [ + { + "match": "X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?b)(?(DEFINE)(a+))(?&DEFINE)/", + "haystack": "bbbb", + "match": [ + { + "match": "bb", + "group1": "b" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?b)(?(DEFINE)(a+))(?&DEFINE)/", + "haystack": "baaab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[,;:])(?=.{8,16})(?!.*[\\s])/", + "haystack": "\\ Fred:099", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=.*X)X$/", + "haystack": "\\ X", + "match": [ + { + "match": "X" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?s)(?=.*?)b/", + "haystack": "aabc", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(Z)(a)\\2{1,2}?(?-i)\\1X/i", + "haystack": "ZaAAZX", + "match": [ + { + "match": "ZaAAZX", + "group1": "Z", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[s[:digit:]\\E-H]+/", + "haystack": "s09-H", + "match": [ + { + "match": "s09-H" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[s[:digit:]\\Q\\E-H]+/", + "haystack": "s09-H", + "match": [ + { + "match": "s09-H" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a+(?:|b)a/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(A(*COMMIT)|B)D/", + "haystack": "ABD", + "match": [ + { + "match": "ABD", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(A(*COMMIT)|B)D/", + "haystack": "XABD", + "match": [ + { + "match": "ABD", + "group1": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(A(*COMMIT)|B)D/", + "haystack": "BAD", + "match": [ + { + "match": "BAD", + "group1": "A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?1)(A(*COMMIT)|B)D/", + "haystack": "ABXABD", + "match": [ + { + "match": "ABD", + "group1": "B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?1)(A(*COMMIT)|B)D/", + "haystack": "ABX", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(? 1? (?=(?2)?) 1 2 (?('cond')|3)))\n \\A\n ()\n (?&m)\n \\Z/x", + "haystack": "123", + "match": [ + { + "match": "123", + "group3": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?:\n(?: A| (1? (?=(?2)?) (1) 2 (?('cond')|3)) )\n(Z)\n)+$/x", + "haystack": "AZ123Z", + "match": [ + { + "match": "AZ123Z", + "group1": "123", + "group3": "1", + "group4": "Z" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?:\n(?: A| (1? (?=(?2)?) (1) 2 (?('cond')|3)) )\n(Z)\n)+$/x", + "haystack": "AZ12Z", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^ (?(DEFINE) ( (?!(a)\\2b)..) ) ()(?1) /x", + "haystack": "acb", + "match": [ + { + "match": "ac", + "group3": "" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^ (?(DEFINE) ( (?!(a)\\2b)..) ) ()(?1) /x", + "haystack": "aab", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?>ab|abab){1,5}?M/", + "haystack": "abababababababababababM", + "match": [ + { + "match": "abababababM" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?>ab|abab){2}?M/", + "haystack": "abababM", + "match": [ + { + "match": "ababM" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(?=(a))a)+k)/", + "haystack": "bbak", + "match": [ + { + "match": "ak", + "group1": "ak", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/((?(?=(a))a|)+k)/", + "haystack": "bbak", + "match": [ + { + "match": "ak", + "group1": "ak", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(?!(b))a|b)+k/", + "haystack": "ababbalbbadabak", + "match": [ + { + "match": "abak", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!(b))c|b/", + "haystack": "Ab", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?!(b))c|b/", + "haystack": "Ac", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(b))b|c/", + "haystack": "Ab", + "match": [ + { + "match": "b", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=(b))b|c/", + "haystack": "Ac", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)\\2)$/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)\\2)$/", + "haystack": "aba", + "match": [ + { + "match": "aba", + "group1": "aba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)\\2)$/", + "haystack": "abcba", + "match": [ + { + "match": "abcba", + "group1": "abcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)\\2)$/", + "haystack": "ababa", + "match": [ + { + "match": "ababa", + "group1": "ababa", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)\\2)$/", + "haystack": "abcdcba", + "match": [ + { + "match": "abcdcba", + "group1": "abcdcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "a", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "aba", + "match": [ + { + "match": "aba", + "group1": "aba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "abba", + "match": [ + { + "match": "abba", + "group1": "abba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "abcba", + "match": [ + { + "match": "abcba", + "group1": "abcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "ababa", + "match": [ + { + "match": "ababa", + "group1": "ababa", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "abccba", + "match": [ + { + "match": "abccba", + "group1": "abccba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "abcdcba", + "match": [ + { + "match": "abcdcba", + "group1": "abcdcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((.)(?1)\\2|.?)$/", + "haystack": "abcddcba", + "match": [ + { + "match": "abcddcba", + "group1": "abcddcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.)(\\1|a(?2))/", + "haystack": "bab", + "match": [ + { + "match": "bab", + "group1": "b", + "group2": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(.|(.)(?1)?\\2)$/", + "haystack": "abcba", + "match": [ + { + "match": "abcba", + "group1": "abcba", + "group2": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=(a))abc|def)/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!(a))def|abc)/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?=(a)(*ACCEPT))abc|def)/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?(?!(a)(*ACCEPT))def|abc)/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?1)\\d{3}(a)/", + "haystack": "a123a", + "match": [ + { + "match": "a123a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/<(?x:[a b])>/xx", + "haystack": "< >", + "match": [ + { + "match": "< >" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/<(?:[a b])>/xx", + "haystack": "< >", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/<(?xxx:[a b])>/", + "haystack": "< >", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/<(?-x:[a b])>/xx", + "haystack": "< >", + "match": [ + { + "match": "< >" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/[[:digit:]-]+/", + "haystack": "12-24", + "match": [ + { + "match": "12-24" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?a?)X)^(?&optional_a)a$/", + "haystack": "aa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?a?)X)^(?&optional_a)a$/", + "haystack": "a", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)b(?1)a/", + "haystack": "abaa", + "match": [ + { + "match": "abaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)b(?1)a/", + "haystack": "aba", + "match": [ + { + "match": "aba", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)b(?1)a/", + "haystack": "baa", + "match": [ + { + "match": "baa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)b(?1)a/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b(?1)a/", + "haystack": "abaa", + "match": [ + { + "match": "abaa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b(?1)a/", + "haystack": "aba", + "match": [ + { + "match": "aba", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b(?1)a/", + "haystack": "baa", + "match": [ + { + "match": "baa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b(?1)a/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)++b(?1)a/", + "haystack": "abaa", + "match": [ + { + "match": "abaa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)++b(?1)a/", + "haystack": "aba", + "match": [ + { + "match": "aba", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)++b(?1)a/", + "haystack": "baa", + "match": [ + { + "match": "baa", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)++b(?1)a/", + "haystack": "ba", + "match": [ + { + "match": "ba", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b/", + "haystack": "b", + "match": [ + { + "match": "b", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b/", + "haystack": "ab", + "match": [ + { + "match": "ab", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a?)+b/", + "haystack": "aaab", + "match": [ + { + "match": "aaab", + "group1": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?=a+)a(a+)++b/", + "haystack": "aab", + "match": [ + { + "match": "aab", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=\\G.)/g", + "haystack": "abc", + "match": [ + { + "match": "" + }, + { + "match": "" + }, + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?=.(*:X))(*SKIP:X)(*F)|(.)/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?>(*:X))(*SKIP:X)(*F)|(.)/", + "haystack": "abc", + "match": [ + { + "match": "a", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?:(*:X))(*SKIP:X)(*F)|(.)/", + "haystack": "abc", + "match": [ + { + "match": "b", + "group1": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?>a(*:1))(?>b(*:1))(*SKIP:1)x|.*/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?>a(*:1))(?>b)(*SKIP:1)x|.*/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a(*ACCEPT:X)b/", + "haystack": "abc", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?=a(*ACCEPT:QQ)bc)axyz/", + "haystack": "axyz", + "match": [ + { + "match": "axyz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?(DEFINE)(a(*ACCEPT:X)))(?1)b/", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a(*F:X)b/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?(DEFINE)(a(*F:X)))(?1)b/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a(*COMMIT:X)b/", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})(?(DEFINE)(a(*COMMIT:X)))(?1)b/", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a+(*:Z)b(*COMMIT:X)(*SKIP:Z)c|.*/", + "haystack": "aaaabd", + "match": [ + { + "match": "bd" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a+(*:Z)b(*COMMIT:X)(*SKIP:X)c|.*/", + "haystack": "aaaabd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(??{\"\"})a(*COMMIT:X)b/", + "haystack": "axabc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i)A(?^)B(?^x:C D)(?^i)e f/", + "haystack": "aBCDE F", + "match": [ + { + "match": "aBCDE F" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?i)A(?^)B(?^x:C D)(?^i)e f/", + "haystack": "aBCDEF", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?i)A(?^)B(?^x:C D)(?^i)e f/", + "haystack": "AbCDe f", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*pla:foo).{6}/", + "haystack": "abcfoobarxyz", + "match": [ + { + "match": "foobar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*pla:foo).{6}/", + "haystack": "abcfooba", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*positive_lookahead:foo).{6}/", + "haystack": "abcfoobarxyz", + "match": [ + { + "match": "foobar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*pla:foo).{6}|a..)/", + "haystack": "foobarbaz", + "match": [ + { + "match": "foobar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*pla:foo).{6}|a..)/", + "haystack": "abcfoobar", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookahead:foo).{6}|a..)/", + "haystack": "foobarbaz", + "match": [ + { + "match": "foobar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookahead:foo).{6}|a..)/", + "haystack": "abcfoobar", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*plb:foo)bar/", + "haystack": "abcfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*plb:foo)bar/", + "haystack": "abcbarfoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*positive_lookbehind:foo)bar/", + "haystack": "abcfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*positive_lookbehind:foo)bar/", + "haystack": "abcbarfoo", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(*plb:foo)bar|baz)/", + "haystack": "abcfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*plb:foo)bar|baz)/", + "haystack": "bazfoobar", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*plb:foo)bar|baz)/", + "haystack": "abcbazfoobar", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*plb:foo)bar|baz)/", + "haystack": "foobazfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookbehind:foo)bar|baz)/", + "haystack": "abcfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookbehind:foo)bar|baz)/", + "haystack": "bazfoobar", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookbehind:foo)bar|baz)/", + "haystack": "abcbazfoobar", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*positive_lookbehind:foo)bar|baz)/", + "haystack": "foobazfoobar", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(*nlb:foo)bar/", + "haystack": "abcbarfoo", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*nlb:foo)bar/", + "haystack": "abcfoobar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*negative_lookbehind:foo)bar/", + "haystack": "abcbarfoo", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*negative_lookbehind:foo)bar/", + "haystack": "abcfoobar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(*nlb:foo)bar|baz)/", + "haystack": "abcfoobaz", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*nlb:foo)bar|baz)/", + "haystack": "abcbarbaz", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?(*nlb:foo)bar|baz)/", + "haystack": "abcfoobar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(*negative_lookbehind:foo)bar|baz)/", + "haystack": "abcfoobaz", + "match": [ + { + "match": "baz" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(*negative_lookbehind:foo)bar|baz)/", + "haystack": "abcbarbaz", + "match": [ + { + "match": "bar" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?(*negative_lookbehind:foo)bar|baz)/", + "haystack": "abcfoobar", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(*atomic:a+)\\w/", + "haystack": "aaab", + "match": [ + { + "match": "aaab" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(*atomic:a+)\\w/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/ (? \\w+ )* \\. /xi ", + "haystack": "pokus.", + "match": [ + { + "match": "pokus.", + "group1": "pokus" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE) (? \\w+ ) ) (?&word)* \\./xi ", + "haystack": "pokus.", + "match": [ + { + "match": "pokus." + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE) (? \\w+ ) ) ( (?&word)* ) \\./xi ", + "haystack": "pokus.", + "match": [ + { + "match": "pokus.", + "group2": "pokus" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?&word)* (?(DEFINE) (? \\w+ ) ) \\./xi ", + "haystack": "pokus.", + "match": [ + { + "match": "pokus." + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?&word)* \\. (? \\w+ )/xi ", + "haystack": "pokus.hokus", + "match": [ + { + "match": "pokus.hokus", + "group1": "hokus" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?(?=(*:2)b).)/ ", + "haystack": "abc", + "match": [ + { + "match": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?(?=(*:2)b).)/ ", + "haystack": "acb", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?(?!(*:2)b).)/ ", + "haystack": "acb", + "match": [ + { + "match": "ac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a(?(?!(*:2)b).)/ ", + "haystack": "abc", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/(?:a|ab){1}+c/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(a|ab){1}+c/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(a+){1}+a/", + "haystack": "aaaa", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(a|ab))(?1){1}+c/", + "haystack": "abc", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?:a|(?=b)|.)*\\z/", + "haystack": "abc", + "match": [ + { + "match": "abc" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?:a|(?=b)|.)*/", + "haystack": "abc", + "match": [ + { + "match": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(*SKIP)x)|c/", + "haystack": "abcd", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=a(*SKIP)x)|d/", + "haystack": "abcd", + "match": [ + { + "match": "d" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(?=.(?<=x)))/ ", + "haystack": "abx", + "match": [ + { + "match": "" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=(?=(?<=a)))b/", + "haystack": "ab", + "match": [ + { + "match": "b" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?a)(?()b)((?<=b).*)$/", + "haystack": "abc", + "match": [ + { + "match": "abc", + "group1": "a", + "group2": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a\\1?){4}$/", + "haystack": "aaaa", + "match": [ + { + "match": "aaaa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(a\\1?){4}$/", + "haystack": "aaaaaa", + "match": [ + { + "match": "aaaaaa", + "group1": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^((\\1+)|\\d)+133X$/", + "haystack": "111133X", + "match": [ + { + "match": "111133X", + "group1": "11", + "group2": "11" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "The quick brown fox jumps over the lazy dog.", + "match": [ + { + "match": "The quick brown fox jumps over the lazy dog", + "group1": "g" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "Jackdaws love my big sphinx of quartz.", + "match": [ + { + "match": "Jackdaws love my big sphinx of quartz", + "group1": "z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "Pack my box with five dozen liquor jugs.", + "match": [ + { + "match": "Pack my box with five dozen liquor jugs", + "group1": "s" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "The quick brown fox jumps over the lazy cat.", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "Hackdaws love my big sphinx of quartz.", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/^(?>.*?([A-Z])(?!.*\\1)){26}/i ", + "haystack": "Pack my fox with five dozen liquor jugs.", + "noMatch": true + }, + { + "matchExpected": 0, + "pattern": "/(?<=X(?(DEFINE)(A)))X(*F)/", + "haystack": "AXYZ", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/(?<=X(?(DEFINE)(A)))./", + "haystack": "AXYZ", + "match": [ + { + "match": "Y" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=X(?(DEFINE)(.*))Y)./", + "haystack": "AXYZ", + "match": [ + { + "match": "Z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?<=X(?(DEFINE)(Y))(?1))./", + "haystack": "AXYZ", + "match": [ + { + "match": "Z" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?(DEFINE)(?bar))(?\\x{8c}748364<", + "match": [ + { + "match": "\\x8c748364" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{65536/", + "haystack": ">a{65536<", + "match": [ + { + "match": "a{65536" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a\\K.(?0)*/", + "haystack": "abac", + "match": [ + { + "match": "c" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a\\K.(?1)*)/", + "haystack": "abac", + "match": [ + { + "match": "c", + "group1": "abac" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,3}B/", + "haystack": "XBBB", + "match": [ + { + "match": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,3}B/", + "haystack": "XaBBB", + "match": [ + { + "match": "aB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,3}B/", + "haystack": "XaaBBB", + "match": [ + { + "match": "aaB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,3}B/", + "haystack": "XaaaBBB", + "match": [ + { + "match": "aaaB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,3}B/", + "haystack": "XaaaaBBB", + "match": [ + { + "match": "aaaB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{,}B/", + "haystack": "Xa{,}BBB", + "match": [ + { + "match": "a{,}B" + } + ] + }, + { + "matchExpected": 0, + "pattern": "/a{,}B/", + "haystack": "XBBB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/a{,}B/", + "haystack": "XaBBB", + "noMatch": true + }, + { + "matchExpected": 1, + "pattern": "/X{/", + "haystack": "ZZX{}YY", + "match": [ + { + "match": "X{" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{A/", + "haystack": "ZZX{ABC}", + "match": [ + { + "match": "X{A" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{}/", + "haystack": "ZZX{}YZ", + "match": [ + { + "match": "X{}" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{1234/", + "haystack": "ZZX{123456", + "match": [ + { + "match": "X{1234" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{12ABC}/", + "haystack": "ZZX{12ABC}Y", + "match": [ + { + "match": "X{12ABC}" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{1,/", + "haystack": "ZZX{1,...", + "match": [ + { + "match": "X{1," + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{,9/", + "haystack": "ZZX{,9}abc", + "match": [ + { + "match": "X{,9" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/X{,9]/", + "haystack": "ZZX{,9]..", + "match": [ + { + "match": "X{,9]" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(A)(?-1)(?+1)(B)/", + "haystack": "xxAABBzz", + "match": [ + { + "match": "AABB", + "group1": "A", + "group2": "B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(A)(\\g{ -2 }B)/", + "haystack": "XAABX", + "match": [ + { + "match": "AAB", + "group1": "A", + "group2": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(A)((?-2)B)/", + "haystack": "XAABX", + "match": [ + { + "match": "AAB", + "group1": "A", + "group2": "AB" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a\\c\\X/", + "haystack": "--a\\x1cX--", + "match": [ + { + "match": "a\\x1cX" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(a)\\g{ 1 }/", + "haystack": "baab", + "match": [ + { + "match": "aa", + "group1": "a" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{ 1,2 }/", + "haystack": "Xaaaaa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/a{ 1 , 2 }/", + "haystack": "Xaaaaa", + "match": [ + { + "match": "aa" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/(?'name'ab)\\k{ name }(?P=name)/", + "haystack": "XabababX", + "match": [ + { + "match": "ababab", + "group1": "ab" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A{,}B/", + "haystack": "A{,}B", + "match": [ + { + "match": "A{,}B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A{ , }B/", + "haystack": "A{ , }B", + "match": [ + { + "match": "A{ , }B" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A{ ,3}/", + "haystack": "AAAAAACC", + "match": [ + { + "match": "AAA" + } + ] + }, + { + "matchExpected": 1, + "pattern": "/A{ 3, }/", + "haystack": "BBAAAAAACC", + "match": [ + { + "match": "AAAAAA" + } + ] + } +] diff --git a/testdata/readme.md b/testdata/rust/readme.md similarity index 100% rename from testdata/readme.md rename to testdata/rust/readme.md diff --git a/testresult1.txt b/testresult1.txt new file mode 100644 index 0000000..e69de29