Is There a Function Like String#Scan, But Returning Array of Matchdatas

Is there a function like String#scan, but returning array of MatchDatas?

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 }

Ruby String#scan equivalent to return MatchData

You could easily build your own by exploiting MatchData#end and the pos parameter of String#match. Something like this:

def matches(s, re)
start_at = 0
matches = [ ]
while(m = s.match(re, start_at))
matches.push(m)
start_at = m.end(0)
end
matches
end

And then:

>> matches("foo _bar_ _baz_ hashbang", /_[^_]+_/)
=> [#<MatchData "_bar_">, #<MatchData "_baz_">]
>> matches("_a_b_c_", /_[^_]+_/)
=> [#<MatchData "_a_">, #<MatchData "_c_">]
>> matches("_a_b_c_", /_([^_]+)_/)
=> [#<MatchData "_a_" 1:"a">, #<MatchData "_c_" 1:"c">]
>> matches("pancakes", /_[^_]+_/)
=> []

You could monkey patch that into String if you really wanted to.

Looking for Regexp#match_all

See Is there a function like String#scan, but returning array of MatchDatas?

It looks like your best bet is to use String#scan and Regexp.last_match.

String.scan returning empty array in Ruby

The main issue is that your capturing groups (the stuff matched by whatever's in parentheses) aren't capturing what you want.

Let's say you want just the username and domain. You should use something along the lines of /\b(\w+(?:\.\w+)*)@(\w+(?:\.\w+)*)\.\w+\b/. As it stands, your pattern matches the input text, but the groups don't actually capture any text.

Also, why not just use /([\w\.]+)@([\w\.]+)\.\w+/? (not too familiar with ruby's regex engine, but that should be about right... you don't even need to check for word boundaries if you're using greedy quantifiers)

Getting each instance of matched string from MatchData

Turns out that simply looping/displaying through each instance of #<MatchData ""> did the trick

Get index of string scan results in ruby

Try this:

res = []
"abab".scan(/a/) do |c|
res << [c, $~.offset(0)[0]]
end

res.inspect # => [["a", 0], ["a", 2]]

What's the difference between scan and match on Ruby string

Short answer: scan will return all matches. This doesn't make it superior, because if you only want the first match, str.match[2] reads much nicer than str.scan[0][1].

ruby-1.9.2-p290 :002 > 'a 1-night stay, a 2-night stay'.scan(/(a )?(\d*)[- ]night/i).to_a
=> [["a ", "1"], ["a ", "2"]]
ruby-1.9.2-p290 :004 > 'a 1-night stay, a 2-night stay'.match(/(a )?(\d*)[- ]night/i).to_a
=> ["a 1-night", "a ", "1"]

How to access the results of .match as string value in Crystal lang

What if I want to convert to a string merely the first match?

puts "Happy days"[/[a-z]+/i]?
puts "Happy days".match(/[a-z]+/i).try &.[0]

It will try to match a string against /[a-z]+/i regex and if there is a match, Group 0, i.e. the whole match, will be output. Note that the ? after [...] will make it fail gracefully if there is no match found. If you just use puts "??!!"[/[a-z]+/i], an exception will be thrown.

See this online demo.

If you want the functionality similar to String#scan that returns all matches found in the input, you may use (shortened version only left as per @Amadan's remark):

matches = str.scan(re).map(&.string)

Output of the code above:

["Happy days", "Happy days"]

Note that:

  • String::scan will return an array of Regex::MatchData for each match.
  • You can call .string on the match to return the actual matched text.

How to match all occurrences of a regular expression in Ruby

Using scan should do the trick:

string.scan(/regex/)

Matching position in gsub or scan

"hello".gsub(/./) { Regexp.last_match.offset(0).first }
=> "01234"

See Regexp.last_match and MatchData.



Related Topics



Leave a reply



Submit