Find overlapping Regexp matches
Asked Answered
M

2

13

I want to find all matches within a given string including overlapping matches. How could I achieve it?

# Example
"a-b-c-d".???(/\w-\w/)  # => ["a-b", "b-c", "c-d"] expected

# Solution without overlapped results
"a-b-c-d".scan(/\w-\w/) # => ["a-b", "c-d"], but "b-c" is missing
Mil answered 7/12, 2016 at 22:34 Comment(0)
P
16

Use capturing inside a positive lookahead:

"a-b-c-d".scan(/(?=(\w-\w))/).flatten
 # => ["a-b", "b-c", "c-d"]

See Ruby demo

Photochronograph answered 7/12, 2016 at 22:37 Comment(2)
Works perfectly, also with complex patterns. "abaca".scan(/(?=(\w)(?:(?!\1)(\w))\1)/) #=> [["a", "b"], ["a", "c"]].Mil
...or positive lookbehind: "a-b-c-d".scan(/(?<=(\w-\w))/).flatten.Rabbin
R
4

I suggest a non-regex solution:

"a-b-c-d".delete('-').each_char.each_cons(2).map { |s| s.join('-') }
  #=> ["a-b", "b-c", "c-d"]

or

"a-b-c-d".each_char.each_cons(3).select.with_index { |_,i| i.even? }.map(&:join)
  #=> ["a-b", "b-c", "c-d"]

or

enum = "a-b-c-d".each_char
a = []
loop do
  a << "%s%s%s" % [enum.next, enum.next, enum.peek]
end
a #=> ["a-b", "b-c", "c-d"]
Rabbin answered 8/12, 2016 at 5:5 Comment(2)
Your last technique is very very neat.Haploid
Nice answer, but I was explicitly asking for a regexp. The pattern above was just the simplest one I found to explain my problem. The pattern I actually use, is (\w)(?:(?!\1)(\w))\1.Mil

© 2022 - 2024 — McMap. All rights reserved.