In many other programming languages, there is a function which takes as a parameter a regular expression and returns an array of string values. This is true of Javascript and Ruby. The .match
in crystal, however, does 1) not seem to accept the global flag and 2) it does not return an array but rather a struct of type Regex::MatchData
. (https://crystal-lang.org/api/0.25.1/Regex/MatchData.html)
As an example the following code:
str = "Happy days"
re = /[a-z]+/i
matches = str.match(re)
puts matches
returns Regex::MatchData("Happy")
I am unsure how to convert this result into a string or why this is not the default as it is in the inspiration language (Ruby). I understand this question probably results from my inexperience dealing with structs and compiled languages but I would appreciate an answer in hopes that it might also help someone else coming from a JS/Ruby background.
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):
str = "Happy days"
re = /[a-z]+/i
matches = [] of String
str.scan(re) do |match|
matches << match[0]
end
puts matches
Output of the code above:
["Happy", "days"]
Note that String::scan
will return an array of Regex::MatchData
for each match. To get the text of the match, just access the first item in the match object.
A shorter way is to use
matches = str.scan(re).map(&.to_a).flatten
See the online demo.