Find index of regex match in string

Viewed 551

Is it possible to find the index of a match in regex while still getting the match? For example:

str = "foo [bar] hello [world]"
str.match(/\[(.*?)\]/) { |match,idx| 
  puts match
  puts idx
}

Unfortunately, idx is nil in this example.

My real world problem is a string, where I want to replace certain sub strings, that are wrapped in brackets with parentheses, based on some conditions (e.g. if the string is inside a blacklist), e.g. "foo [bar] hello [world]" should become "foo [bar] hello (world)" when the word world is in a blacklist.

2 Answers

You can use String#gsub:

blacklist = ["world"]
str = "foo [bar] hello [world]"

str.gsub(/\[(\w*?)\]/) { |m|
  blacklist.include?($1) ? "(#{$1})" : m
}

#=> "foo [bar] hello (world)"

If you want an Enumerator with every match object, you can use :

def matches(string, regex)
  position = 0
  Enumerator.new do |yielder|
    while match = regex.match(string, position)
      yielder << match
      position = match.end(0)
    end
  end
end

As an example :

p matches("foo [bar] hello [world]", /\[(.*?)\]/).to_a
# [#<MatchData "[bar]" 1:"bar">, #<MatchData "[world]" 1:"world">]
p matches("foo [bar] hello [world]", /\[(.*?)\]/).map{|m| [m[1], m.begin(0)]}
# [["bar", 4], ["world", 16]]

You can get the matched string and its index from the match object.

But actually, it looks like you need gsub with a block:

"foo [bar] hello [world]".gsub(/\[(.*?)\]/){ |m| # define logic here }
Related