Regexes

Pattern matching against strings

Regular expressions are a computer science concept where simple patterns describe the format of text. Pattern matching is the process of applying these patterns to actual text to look for matches.

The Most modern regular expression facilities are more powerful than traditional regular expressions due to the influence of languages such as Perl, but the short-hand term regex has stuck and continues to mean regular expression-like pattern matching.

In Perl 6, although they are capable of much more than regular languages, we continue to call them regex.

Lexical conventions

Perl 6 has special syntax for writing regexes:

m/abc/;         # a regex that is immediately matched against $_
rx/abc/;        # a Regex object
/abc/;          # a Regex object

The first two can use delimiters other than the slash:

m{abc};
rx{abc};

Note that neither the colon : nor round parentheses can be delimiters; the colon is forbidden because it would clash with adverbs, such as rx:i/abc/ (case insensitive regexes), and round parentheses would indicate a function call instead.

Whitespace in regexes is generally ignored (except with the :s or :sigspace adverb).

As in the rest of Perl 6, comments in regexes start with a hash character # and go upto the rest of the line.

Literals

The simplest case of a regex is a constant string. Matching a string against that regex searches for that string:

if 'properly' ~~ m/ perl / {
    say "'properly' contains 'perl'";
}

Alphanumeric characters and the underscore _ are literal matches. All other characters must either be escaped with a backslash (for example \: to match a colon), or included in quotes:

/ 'two words' /     # matches 'two words' including the blank
/ "a:b"       /     # matches 'a:b' including the colon

The hash character # cannot be escaped with a backslash, because that would collide with the unspace syntax. So to match a hash character, you need to quote it:

/'#'/               # hashes must be quoted, cannot be escaped

Strings are searched left to right for the regex, so its enough if a substring matches the regex:

if 'abcdef' ~~ / de / {
    say ~$/;            # de
    say $/.prematch;    # abc
    say $/.postmatch;   # f
    say $/.from;        # 3
    say $/.to;          # 5
};

Match results are stored in the $/ variable, and are also returned from the match. The result is of type Match.

Wildcards and character classes

Dot to match any character

An unescaped dot . in a regex matches any single character.

So these all match:

'perl' ~~ / per . /;    # matches the whole string
'perl' ~~ /per./;       # the same; whitespace is ignored
'perl' ~~ / pe.l /;     # the . matches the r
'speller' ~~ / pe.l/;   # the . matches the first l

This doesn't match:

'perl' ~~ /. per /

because there is no character to match before per in the target string.

Backslashed, predefined character classes

There are predefined character classes of the form \w. Its negation is written with an upper-case letter

\d matches a single digit (Unicode property N), and \D matches a single character that is not a digit.

'ab42' ~~ /\d/ and say ~$/;     # 4
'ab42' ~~ /\D/ and say ~$/;     # a

Note that not only the Arabic digits (commonly used in the Latin alphabet) match \d, but also digits from other scripts.

Examples for digits are

U+0035 5 DIGIT FIVE
U+07C2 ߂ NKO DIGIT TWO
U+0E53 ๓ THAI DIGIT THREE
U+1B56 ᭖ BALINESE DIGIT SIX

\h matches a single horizontal whitespace character. \H matches a single character that is not a horizontal whitespace character.

Examples for horizontal whitespace characters are

U+0020 SPACE
U+00A0 NO-BREAK SPACE
U+0009 CHARACTER TABULATION
U+2001 EM QUAD

Vertical whitespaces like newline characters are explicitly excluded; those can be matched with \v, and \s matches any kind of whitespace.

\n matches a single, logical newline character. \n is supposed to also match a Windows CR LF codepoing pair; though it is unclear whether the magic happens at the time that external data is read, or at regex match time. \N matches a single character that's not a logical newline.

\s matches a single whitespace character. \S matches a single character that is not a whitspace.

TODO: examples

\t matches a single tab/tabulation character, U+0009. (Note that exotic tabs like the U+000B VERTICAL TABULATION character is not included here). \T matches a single character that is not a tab.

\v matches a single vertical whitespace character. \V match a single character that is not a vertical whitspace.

Examples for vertical whitespace characters:

U+000A LINE FEED
U+000B VERTICAL TABULATION
U+000C CARRIAGE RETURN
U+0085 NEXT LINE
U+2029 PARAGRAPH SEPARATOR

Use \s to match any kind of whitespace, not just vertical whitespace

\w matches a single word character, that is a letter (Unicode category L), a digit or an underscore. \W matches a single character that isn't a word character.

Examples of word characters:

0041 A LATIN CAPITAL LETTER A
0031 1 DIGIT ONE
03B4 δ GREEK SMALL LETTER DELTA
03F3 ϳ GREEK LETTER YOT
0409 Љ CYRILLIC CAPITAL LETTER LJE

Unicode properties

The character classes so far are mostly for convenience; a more systematic approach is the use of Unicode properties. They are called in the form <:property> , where property can be a short or long Unicode property name.

The following list is stolen from the Perl 5 perlunicode documentation:

Short Long
L Letter
LC Cased_Letter
Lu Uppercase_Letter
Ll Lowercase_Letter
Lt Titlecase_Letter
Lm Modifier_Letter
Lo Other_Letter
M Mark
Mn Nonspacing_Mark
Mc Spacing_Mark
Me Enclosing_Mark
N Number
Nd Decimal_Number (also Digit)
Nl Letter_Number
No Other_Number
P Punctuation (also Punct)
Pc Connector_Punctuation
Pd Dash_Punctuation
Ps Open_Punctuation
Pe Close_Punctuation
Pi Initial_Punctuation
(may behave like Ps or Pe depending on usage)
Pf Final_Punctuation
(may behave like Ps or Pe depending on usage)
Po Other_Punctuation
S Symbol
Sm Math_Symbol
Sc Currency_Symbol
Sk Modifier_Symbol
So Other_Symbol
Z Separator
Zs Space_Separator
Zl Line_Separator
Zp Paragraph_Separator
C Other
Cc Control (also Cntrl)
Cf Format
Cs Surrogate
Co Private_Use
Cn Unassigned

So for example <:Lu> matches a single, upper-case letter.

Negation works as <:!category> , so <:!Lu> matches a single character that isn't an upper-case letter.

Several category can be combined with one of these infix operators:

Operator Meaning
+ set union
| set union
& set intersection
- set difference (first minus second)
^ symmetric set intersection / XOR

So for example to either match a lower-case letter or a number, one can write <:Ll+:N> or <:Ll+:Number> or <+ :Lowercase_Letter + :Number> .

(Grouping of set operations with round parens inside character classes is supposed to work, but not supported by Rakudo at the time of writing).

Enumerated character classes and ranges

Sometimes the pre-existing wildcards and character classes are just not enough. Fortunately, defining your own is simple enough. Between <[ ]> , you can put any number of single characters and ranges of characters (expressed with two dots between the end points) between them, with or without whitespace.

"abacabadabacaba" ~~ / <[ a .. c 1 2 3 ]> /

In between the < > , you can also use the same operators for categories (+, |, &, -, ^) to combine multiple range definitions and even mix in some of the unicode categories above. Another thing you are allowed to write between the [ ] is the backslashed forms for character classes.

/ <[\d] - [13579]> /
# not quite the same as
/ <[02468]>
# because the first one also contains "weird" unicodey digits

Quantifier

A quantifier makes a preceding atom match not exactly once, but rather a variable number of times. For example a+ matches one or more a characters.

Quantifiers bind tighter than concatenation, so ab+ matches one a followed by one or more bs. This is different for quotes, so 'ab'+ matches the strings ab, abab, ababab etc.

One or more: +

The + quantifier makes the preceding atom match one or more times, with no upper limit.

For example to match strings of the form key=value, you can write a regex like this:

/ \w+ '=' \w+ /

Zero or more: *

The * quantifier makes the preceding atom match zero or more times, with no upper limit.

For example to optional whitespace between a and b you can write

/ a \s* b /

Zero or one match: ?

The ? quantifier makes the preceding atom match zero or one time.

General quantifier: ** min..max

To quantifier an atom an arbitrary number of times, you can say for example a ** 2..5 to match the character a at least twice and at most 5 times

If minimal and maximal number of matches are the same, a single integer is possible: a ** 5 to match a exactly five times.

Alternation

TODO

Grouping and Capturing

TODO