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