How to match all occurrences of a regular expression in Ruby?
In Ruby, you typically use the String#scan
method to find all matches of a given regular expression in a string. For example:
text = "abc 123 def 456" matches = text.scan(/\d+/) # => ["123", "456"]
This returns an array containing all the substrings that match the regex. Below are more details and variations.
1. Basic Usage with String#scan
text = "Hello 123, goodbye 456" pattern = /\d+/ results = text.scan(pattern) p results # Output: ["123", "456"]
text.scan(pattern)
returns an array of all non-overlapping matches.
2. Capturing Groups
If your regex includes capturing groups, scan
will return an array of arrays, each containing the capture groups for a match:
text = "first: 123, second: 456" pattern = /(\w+):\s+(\d+)/ results = text.scan(pattern) # => [["first", "123"], ["second", "456"]]
Here, each element is [group1, group2]
. If your pattern had 3 capture groups, each element would have 3 elements, etc.
3. Processing Each Match with a Block
You can also pass a block to scan
:
text = "abc 123 def 456" text.scan(/\d+/) do |match| puts "Found digits: #{match}" end
- In this scenario,
scan
still iterates over all matches, but instead of returning an array, it will yield each match to the block.
4. Using match
, =~
, or match?
for Single Occurrences
string.match(regex)
returns the first match (as aMatchData
object) ornil
.string =~ regex
returns the 0-based index of the first match ornil
.regex.match?(string)
(Ruby 2.4+) quickly checks if there’s any match, returning boolean.
These methods only handle one occurrence; use scan
for all occurrences.
5. Handling Overlapping Matches
A subtle point is that scan
finds non-overlapping matches by default. For example:
"aaaa".scan(/aa/) # => ["aa", "aa"]
This returns ["aa", "aa"]
, which is non-overlapping. If you want overlapping matches (like ["aa", "aa", "aa"]
for aaa
?), you’d need a custom approach, often manually shifting indices in a loop. But for most standard use cases, scan
suffices.
6. Example: Extracting Phone Numbers or Emails
text = "Contact me at me@example.com or 555-123-4567" emails = text.scan(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z]{2,}\b/i) phones = text.scan(/\b\d{3}-\d{3}-\d{4}\b/)
- Each
scan
returns an array of all found emails or phone numbers.
7. Summary
- Use
String#scan
to find all matches of a regex in a string, returning an array of match results. - If your regex has capturing groups,
scan
returns an array of arrays (one subarray per group). - You can pass a block to
scan
if you want to handle each match as it’s found rather than storing them all. - Single-match methods like
match
or=~
only return the first occurrence. - For overlapping matches, you need a more manual approach.
Bonus: Strengthen Your Regex & Coding Interview Skills
If you’re honing your Ruby or regex abilities—or preparing for technical interviews—check out the following DesignGurus.io resources:
-
Grokking the Coding Interview: Patterns for Coding Questions
- Improve your problem-solving approach and gain confidence in interviews.
-
Grokking System Design Fundamentals
- For higher-level design thinking—useful in many senior engineering interviews.
Looking for personalized feedback? Explore Mock Interviews with ex-FAANG engineers:
Lastly, don’t miss the free tutorials on the DesignGurus.io YouTube channel.
Conclusion: Use String#scan
in Ruby to match all occurrences of a regex. For example:
"abc123 def456".scan(/\d+/) # => ["123", "456"]
This returns an array of all non-overlapping matches found in the string.