Regex

Search and replace text with compiled regular expressions
]help •r

•r — Regular expressions

•r pattern compiles a regular expression. It returns a keyed vector of two functions that share the pattern. p.matches text gives a table of the matches, as a record of columns: text, the matched text; position, its position in characters from 0; and groups, the text of each group, which is empty for a group that took no part. template p.replace text replaces each match with template, expanded with the match’s groups.

Natively the pattern is a Rust regex, with the regex crate’s syntax. Flags go in the pattern, as in (?i), and templates use $1, ${name} and $$. In the browser the pattern is a JavaScript regular expression, with JavaScript’s syntax, and templates use $1, $<name> and $$. Regular expressions covers each function.

p←•r "([a-z]+)([0-9]+)"
p.matches "ab12 cd3"           ⍝ ["text":["ab12" "cd3"] "position":[0 5]ₓ "groups":("ab" "12"⋄"cd" "3")]
"$2:$1" p.replace "ab12 cd3"   ⍝ "12:ab 3:cd"

Errors: DOMAIN for invalid patterns and non-text arguments; SYNTAX for the wrong valence; LIMIT for oversized results.

Natively, patterns use Rust regex syntax. In the browser they use JavaScript’s. p.matches gives a table of the matches, as a record of columns. Here p finds runs of digits:

p←•r "[0-9]+"
p.matches "abc123def45"
["text":["123" "45"] "position":[3 9]ₓ "groups":[0⍴⊂"" 0⍴⊂""]]

Matches don’t overlap. Positions count characters, and ≢¨ of the text column gives each match’s length. A text with no match gives a table with no rows:

m←(•r "é|🐈+").matches "aé🐈🐈z"
m.position
≢¨m.text
(•r "é|🐈+").matches "abc"
[1 2]ₓ
[1 2]ₓ
["text":0⍴⊂"" "position":⍬ₓ "groups":0⍴⊂0⍴⊂""]

The groups column holds the captured strings of each match, without the whole match. An unmatched optional capture gives "":

p←•r "([a-z]+)([0-9]+)"
(p.matches "ab12 cd3").groups
("ab" "12"⋄"cd" "3")

template p.replace text replaces each match with template. In a native template, $0 is the whole match and $$ is a literal $. An unknown or unmatched capture expands to "". In the browser, templates use JavaScript’s syntax, where $<word> names a group:

p←•r "(?P<word>[a-z]+)([0-9]+)"
"${word}:$2:$$" p.replace "ab12"
ab:12:$

Natively, inline flags change how a pattern matches. (?i) ignores case. (?m) makes ^ and $ match at each line break. (?s) makes . match line breaks too. Use Each to search several strings:

p←•r "(?i)cat"
{≢(p.matches ⍵).text}¨"Cat cat" "dog"
[2 0]ₓ

Empty matches occur at character boundaries:

p←•r ""
(p.matches "é🐈").position
'-' p.replace "é🐈"
[0 1 2]ₓ
-é-🐈-

lib/regex.bpl supplies pattern f regex_replace text. It applies f to each matched string and keeps the text between matches:

[regex_replace]←•load "../lib/regex.bpl"
"[0-9]+" {⍕⊽•json⍵}regex_replace "a12 b3"
a24 b6