class Regex
Overview
A Regex
represents a regular expression, a pattern that describes the
contents of strings. A Regex
can determine whether or not a string matches
its description, and extract the parts of the string that match.
A Regex
can be created using the literal syntax, in which it is delimited by
forward slashes (/
):
/hay/ =~ "haystack" # => 0
/y/.match("haystack") # => Regex::MatchData("y")
See Regex
literals in the language reference.
Interpolation works in regular expression literals just as it does in string literals. Be aware that using this feature will cause an exception to be raised at runtime, if the resulting string would not be a valid regular expression.
x = "a"
/#{x}/.match("asdf") # => Regex::MatchData("a")
x = "("
/#{x}/ # raises ArgumentError
When we check to see if a particular regular expression describes a string, we can say that we are performing a match or matching one against the other. If we find that a regular expression does describe a string, we say that it matches, and we can refer to a part of the string that was described as a match.
Here "haystack"
does not contain the pattern /needle/
, so it doesn't match:
/needle/.match("haystack") # => nil
Here "haystack"
contains the pattern /hay/
, so it matches:
/hay/.match("haystack") # => Regex::MatchData("hay")
Regex methods that perform a match usually return a truthy value if there was
a match and nil
if there was no match. After performing a match, the
special variable $~
will be an instance of Regex::MatchData
if it matched, nil
otherwise.
When matching a regular expression using =~
(either String#=~
or
Regex#=~
), the returned value will be the index of the first match in the
string if the expression matched, nil
otherwise.
/stack/ =~ "haystack" # => 3
"haystack" =~ /stack/ # => 3
$~ # => Regex::MatchData("stack")
/needle/ =~ "haystack" # => nil
"haystack" =~ /needle/ # => nil
$~ # raises Exception
When matching a regular expression using #match
(either String#match
or
Regex#match
), the returned value will be a Regex::MatchData
if the expression
matched, nil
otherwise.
/hay/.match("haystack") # => Regex::MatchData("hay")
"haystack".match(/hay/) # => Regex::MatchData("hay")
$~ # => Regex::MatchData("hay")
/needle/.match("haystack") # => nil
"haystack".match(/needle/) # => nil
$~ # raises Exception
Regular expressions have their own language for describing strings.
Many programming languages and tools implement their own regular expression language, but Crystal uses PCRE2, a popular C library, with JIT compilation enabled for providing regular expressions. Here give a brief summary of the most basic features of regular expressions - grouping, repetition, and alternation - but the feature set of PCRE2 extends far beyond these, and we don't attempt to describe it in full here. For more information, refer to the PCRE2 documentation, especially the full pattern syntax or syntax quick reference.
NOTE Prior to Crystal 1.8 the compiler expected regex literals to follow the original PCRE pattern syntax. The following summary applies to both PCRE and PCRE2.
The regular expression language can be used to match much more than just the
static substrings in the above examples. Certain characters, called
metacharacters,
are given special treatment in regular expressions, and can be used to
describe more complex patterns. To match metacharacters literally in a
regular expression, they must be escaped by being preceded with a backslash
(\
). escape
will do this automatically for a given String.
A group of characters (often called a capture group or
subpattern)
can be identified by enclosing it in parentheses (()
). The contents of
each capture group can be extracted on a successful match:
/a(sd)f/.match("_asdf_") # => Regex::MatchData("asdf" 1:"sd")
/a(sd)f/.match("_asdf_").try &.[1] # => "sd"
/a(?<grp>sd)f/.match("_asdf_") # => Regex::MatchData("asdf" grp:"sd")
/a(?<grp>sd)f/.match("_asdf_").try &.["grp"] # => "sd"
Capture groups are indexed starting from 1. Methods that accept a capture
group index will usually also accept 0 to refer to the full match. Capture
groups can also be given names, using the (?<name>...)
syntax, as in the
previous example.
Following a match, the special variables $N (e.g., $1, $2, $3, ...) can be used to access a capture group. Trying to access an invalid capture group will raise an exception. Note that it is possible to have a successful match with a nil capture:
/(spice)(s)?/.match("spice") # => Regex::MatchData("spice" 1:"spice" 2:nil)
$1 # => "spice"
$2 # => raises Exception
This can be mitigated by using the nilable version of the above: $N?,
(e.g., $1? $2?, $3?, ...). Changing the above to use $2?
instead of $2
would return nil
. $2?.nil?
would return true
.
A character or group can be
repeated
or made optional using an asterisk (*
- zero or more), a plus sign
(+
- one or more), integer bounds in curly braces
({n,m}
) (at least n
, no more than m
), or a question mark
(?
) (zero or one).
/fo*/.match("_f_") # => Regex::MatchData("f")
/fo+/.match("_f_") # => nil
/fo*/.match("_foo_") # => Regex::MatchData("foo")
/fo{3,}/.match("_foo_") # => nil
/fo{1,3}/.match("_foo_") # => Regex::MatchData("foo")
/fo*/.match("_foo_") # => Regex::MatchData("foo")
/fo*/.match("_foooooooo_") # => Regex::MatchData("foooooooo")
/fo{,3}/.match("_foooo_") # => nil
/f(op)*/.match("fopopo") # => Regex::MatchData("fopop" 1:"op")
/foo?bar/.match("foobar") # => Regex::MatchData("foobar")
/foo?bar/.match("fobar") # => Regex::MatchData("fobar")
Alternatives can be separated using a
vertical bar
(|
). Any single character can be represented by
dot
(.
). When matching only one character, specific
alternatives can be expressed as a
character class,
enclosed in square brackets ([]
):
/foo|bar/.match("foo") # => Regex::MatchData("foo")
/foo|bar/.match("bar") # => Regex::MatchData("bar")
/_(x|y)_/.match("_x_") # => Regex::MatchData("_x_" 1:"x")
/_(x|y)_/.match("_y_") # => Regex::MatchData("_y_" 1:"y")
/_(x|y)_/.match("_(x|y)_") # => nil
/_(x|y)_/.match("_(x|y)_") # => nil
/_._/.match("_x_") # => Regex::MatchData("_x_")
/_[xyz]_/.match("_x_") # => Regex::MatchData("_x_")
/_[a-z]_/.match("_x_") # => Regex::MatchData("_x_")
/_[^a-z]_/.match("_x_") # => nil
/_[^a-wy-z]_/.match("_x_") # => Regex::MatchData("_x_")
Regular expressions can be defined with these 3 optional flags:
i
: ignore case (Regex::Options::IGNORE_CASE
)m
: multiline (Regex::Options::MULTILINE
)x
: extended (Regex::Options::EXTENDED
)
/asdf/ =~ "ASDF" # => nil
/asdf/i =~ "ASDF" # => 0
/^z/i =~ "ASDF\nZ" # => nil
/^z/im =~ "ASDF\nZ" # => 5
PCRE2 supports other encodings, but Crystal strings are UTF-8 only, so Crystal regular expressions are also UTF-8 only (by default).
PCRE2 optionally permits named capture groups (named subpatterns) to not be
unique. Crystal exposes the name table of a Regex
as a
Hash
of String
=> Int32
, and therefore requires named capture groups to have
unique names within a single Regex
.
Included Modules
- Regex::PCRE2