Regular expressions
match and =~
A regex literal is written between slashes. match returns a MatchData or nil, and =~ returns the position of the match or nil. The position is what an old-style test uses; the MatchData is what a program needs:
ruby -e 'p "id=42" =~ /id=(\d+)/; p "no id" =~ /id=(\d+)/'
0
nil
match? answers the yes-or-no question and skips building the MatchData, which is the one to use in a condition:
ruby -e 'p "id=42".match?(/id=\d+/); p "nope".match?(/id=\d+/)'
true
false
Named captures
A named group is read by name instead of by number, which keeps a long regex readable and a change to the group order harmless:
ruby -e 'm = "id=42".match(/id=(?<n>\d+)/); puts m[:n]'
42
m[1] still works for the same group, and m.named_captures returns the hash of names to values. A group written (?:...) groups without capturing, which is how a complex pattern stays cheap.
gsub with a block
gsub replaces every match. With a block, the block receives each match and returns the replacement, which is how a rewrite that depends on the text is written:
ruby -e 'p "a1 b2".gsub(/\d/) { |d| (d.to_i * 2).to_s }'
"a2 b4"
A string replacement uses the back references instead: "a1".gsub(/(\w)(\d)/, "\2\1") gives "1a". The block form is easier to read once the replacement needs a lookup or a condition.
Validating a log line
The pattern that earns its keep is the one that checks a whole line and extracts the fields in one pass. \A and \z anchor the match to the start and the end, so a trailing comment or a missing field fails instead of matching halfway:
LOG = /\A(?<date>\d{4}-\d{2}-\d{2}) (?<time>\d{2}:\d{2}:\d{2}) (?<level>[A-Z]+) (?<msg>.+)\z/
line = "2026-11-05 12:00:01 ERROR payment failed"
m = line.match(LOG)
p m[:level]
p m[:msg]
bad = "not a log line"
p bad.match(LOG).nil?
ruby logline.rb
"ERROR"
"payment failed"
true
The named groups are the fields, and the anchors are the validation. A line that does not fit returns nil, which the caller turns into a skip, a counter or an error with the line in it.
What to watch for
^ and $ match the start
and end of a line; \A and
\z match the start and end of the string. A
validation wants the second pair, or a multi-line string validates its
first line only.
A regex that reads is short, anchored and named. When a pattern needs a
comment to explain it, split it into named parts or parse with
StringScanner, which is the next lesson.
Next: Scanning and parsing strings
Article author: Arthur Isaev