Logo

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 a MatchData object) or nil.
  • string =~ regex returns the 0-based index of the first match or nil.
  • 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:

  1. Grokking the Coding Interview: Patterns for Coding Questions

    • Improve your problem-solving approach and gain confidence in interviews.
  2. 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.

CONTRIBUTOR
TechGrind