You need the Regexp#match
method. If you write /\[(.*?)\](.*)/.match('[ruby] regex')
, this will return a MatchData
object. If we call that object matches
, then, among other things:
matches[0]
returns the whole matched string.
matches[n]
returns the nth capturing group ($n
).
matches.to_a
returns an array consisting of matches[0]
through matches[N]
.
matches.captures
returns an array consisting of just the capturing group (matches[1]
through matches[N]
).
matches.pre_match
returns everything before the matched string.
matches.post_match
returns everything after the matched string.
There are more methods, which correspond to other special variables, etc.; you can check MatchData
's docs for more. Thus, in this specific case, all you need to write is
tag, keyword = /\[(.*?)\](.*)/.match('[ruby] regex').captures
Edit 1: Alright, for your harder task, you're going to instead want the String#scan
method, which @Theo used; however, we're going to use a different regex. The following code should work:
# You could inline the regex, but comments would probably be nice.
tag_and_text = / \[([^\]]*)\] # Match a bracket-delimited tag,
\s* # ignore spaces,
([^\[]*) /x # and match non-tag search text.
input = '[ruby] [regex] [rails] one line [foo] [bar] baz'
tags, texts = input.scan(tag_and_text).transpose
The input.scan(tag_and_text)
will return a list of tag–search-text pairs:
[ ["ruby", ""], ["regex", ""], ["rails", "one line "]
, ["foo", ""], ["bar", "baz"] ]
The transpose
call flips that, so that you have a pair consisting of a tag list and a search-text list:
[["ruby", "regex", "rails", "foo", "bar"], ["", "", "one line ", "", "baz"]]
You can then do whatever you want with the results. I might suggest, for instance
search_str = texts.join(' ').strip.gsub(/\s+/, ' ')
This will concatenate the search snippets with single spaces, get rid of leading and trailing whitespace, and replace runs of multiple spaces with a single space.