Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ruby regex to match multiple occurrences of pattern

Tags:

regex

ruby

I am looking to build a ruby regex to match multiple occurrences of a pattern and return them in an array. The pattern is simply: [[.+]]. That is, two left brackets, one or more characters, followed by two right brackets.

This is what I have done:

str = "Some random text[[lead:first_name]] and more stuff [[client:last_name]]"
str.match(/\[\[(.+)\]\]/).captures

The regex above doesn't work because it returns this:

["lead:first_name]] and another [[client:last_name"]

When what I wanted was this:

["lead:first_name", "client:last_name"] 

I thought if I used a noncapturing group that for sure it should solve the issue:

str.match(/(?:\[\[(.+)\]\])+/).captures

But the noncapturing group returns the same exact wrong output. Any idea on how I can resolve my issue?

like image 917
Donato Avatar asked Dec 15 '22 17:12

Donato


2 Answers

The problem with your regex is that the .+ part is "greedy", meaning that if the regex matches both a smaller and larger part of the string, it will capture the larger part (more about greedy regexes).

In Ruby (and most regex syntaxes), you can qualify your + quantifier with a ? to make it non-greedy. So your regex would become /(?:\[\[(.+?)\]\])+/.

However, you'll notice this still doesn't work for what you want to do. The Ruby capture groups just don't work inside a repeating group. For your problem, you'll need to use scan:

"[[a]][[ab]][[abc]]".scan(/\[\[(.+?)\]\]/).flatten
    => ["a", "ab", "abc"]
like image 81
Nathan Wallace Avatar answered Jan 06 '23 05:01

Nathan Wallace


Try this:

 => str.match(/\[\[(.*)\]\].*\[\[(.*)\]\]/).captures
 => ["lead:first_name", "client:last_name"] 

With many occurrences:

 => str
 => "Some [[lead:first_name]] random text[[lead:first_name]] and more [[lead:first_name]] stuff [[client:last_name]]" 
 => str.scan(/\[(\w+:\w+)\]/)
 => [["lead:first_name"], ["lead:first_name"], ["lead:first_name"], ["client:last_name"]] 
like image 41
Philidor Avatar answered Jan 06 '23 05:01

Philidor