7

I need a function to return all matches of a regexp in a string and positions at which the matches are found (I want to highlight matches in the string).

There is String#match that returns MatchData, but only for the first match.

Is there a better way to do this than something like

matches = []
begin
  match = str.match(regexp)
  break unless match
  matches << match
  str = str[match.end(0)..-1]
  retry
end
Leonid Shevtsov
  • 14,024
  • 9
  • 51
  • 82

4 Answers4

11

If you just need to iterate over the MatchData objects you can use Regexp.last_match in the scan-block, like:

string.scan(regex) do
  match_data = Regexp.last_match
  do_something_with(match_data)
end

If you really need an array, you can use:

require 'enumerator' # Only needed for ruby 1.8.6
string.enum_for(:scan, regex).map { Regexp.last_match }
sepp2k
  • 363,768
  • 54
  • 674
  • 675
2

Do you really need the position or is it enough to replace the matches on the fly?

s="I'mma let you finish but Beyonce had one of the best music videos of all time!"
s.gsub(/(Beyonce|best)/, '<b>\1</b>')

=> "I'mma let you finish but Beyonce had one of the best music videos of all time!"

Jonas Elfström
  • 30,834
  • 6
  • 70
  • 106
1

Use the captures method on a successful match.

"foobar".match(/(f)(oobar)/).captures

=> ["f,""oobar"]

Mike McKay
  • 2,388
  • 1
  • 29
  • 32
0

I think at least you can enhance your code a bit:

matches = []
while(match = str.match(regexp)) 
  matches << match
  str = match.post_match
end
khelll
  • 23,590
  • 15
  • 91
  • 109