Ruby Regexp group matching, assign variables on 1 line
You don't want scan
for this, as it makes little sense. You can use String#match
which will return a MatchData
object, you can then call #captures
to return an Array of captures. Something like this:
#!/usr/bin/env ruby
string = "RyanOnRails: This is a test"
one, two, three = string.match(/(^.*)(:)(.*)/i).captures
p one #=> "RyanOnRails"
p two #=> ":"
p three #=> " This is a test"
Be aware that if no match is found, String#match
will return nil, so something like this might work better:
if match = string.match(/(^.*)(:)(.*)/i)
one, two, three = match.captures
end
Although scan
does make little sense for this. It does still do the job, you just need to flatten the returned Array first. one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten
Ruby - best way to extract regex capture groups?
Since v2.4.6, Ruby has had named_captures
, which can be used like this. Just add the ?<some_name>
syntax inside a capture group.
/(\w)(\w)/.match("ab").captures # => ["a", "b"]
/(\w)(\w)/.match("ab").named_captures # => {}
/(?<some_name>\w)(\w)/.match("ab").captures # => ["a"]
/(?<some_name>\w)(\w)/.match("ab").named_captures # => {"some_name"=>"a"}
Even more relevant, you can reference a named capture by name!
result = /(?<some_name>\w)(\w)/.match("ab")
result["some_name"] # => "a"
Ruby one-liner to capture regular expression matches
string = "the quick brown fox jumps over the lazy dog."
extract_string = string[/fox (.*?) dog/, 1]
# => "jumps over the lazy"
extract_array = string.scan(/the (.*?) fox .*?the (.*?) dog/).first
# => ["quick brown", "lazy"]
This approach will also return nil
(instead of throwing an error) if no match is found.
extract_string = string[/MISSING_CAT (.*?) dog/, 1]
# => nil
extract_array = string.scan(/the (.*?) MISSING_CAT .*?the (.*?) dog/).first
# => nil
Ruby regular expression using variable name
The code you think doesn't work, does:
var = "Value"
str = "a test Value"
p str.gsub( /#{var}/, 'foo' ) # => "a test foo"
Things get more interesting if var can contain regular expression meta-characters. If it does and you want those matacharacters to do what they usually do in a regular expression, then the same gsub will work:
var = "Value|a|test"
str = "a test Value"
str.gsub( /#{var}/, 'foo' ) # => "foo foo foo"
However, if your search string contains metacharacters and you do not want them interpreted as metacharacters, then use Regexp.escape like this:
var = "*This*"
str = "*This* is a string"
p str.gsub( /#{Regexp.escape(var)}/, 'foo' )
# => "foo is a string"
Or just give gsub a string instead of a regular expression. In MRI >= 1.8.7, gsub will treat a string replacement argument as a plain string, not a regular expression:
var = "*This*"
str = "*This* is a string"
p str.gsub(var, 'foo' ) # => "foo is a string"
(It used to be that a string replacement argument to gsub was automatically converted to a regular expression. I know it was that way in 1.6. I don't recall which version introduced the change).
As noted in other answers, you can use Regexp.new as an alternative to interpolation:
var = "*This*"
str = "*This* is a string"
p str.gsub(Regexp.new(Regexp.escape(var)), 'foo' )
# => "foo is a string"
Regexp to match multi-line string
You will need to make last group non-capturing:
^(?<FOOTER_TYPE>[ a-zA-Z0-9-]+)?(?<SEPARATOR>:)?(?<FOOTER>(?<=:)(?:.|[\r\n](?![\r\n]))*)?
Make note of:
(?:.|[\r\n](?![\r\n]))*)?
(?:
at the start makes this optional group non-capturing.
Updated Demo
Ruby strange behaviour while single assigning variables in a single line
It first assigns 2
to num_2
, then returns a value and puts it into an array that is assigned to num_1
[11] pry(main)> num_1 = 1, num_2 = 2
=> [1, 2]
[12] pry(main)> num_1 = 1, (num_2 = 2)
=> [1, 2]
[13] pry(main)> num_1 = [1, (num_2 = 2)]
=> [1, 2]
If you want to assign two variables in one line, use a semicolon:
[14] pry(main)> num_1 = 1; num_2 = 2
=> 2
[15] pry(main)> num_1
=> 1
[16] pry(main)> num_2
=> 2
Regexp in ruby - can I use parenthesis without grouping?
Use a non-capturing group:
r = /(?:ab)?(cd)/
Related Topics
Select Arrays Between Date Ranges with Ruby
Why Do I Get a Bcrypt-Ruby Gem Install Error
Can You Eval Code in the Context of a Caller in Ruby
3 Equals or Case Equality Operator
Nokogiri Was Built Against Libxml Version 2.7.7, But Has Dynamically Loaded 2.7.3
Google Maps, Ruby on Rails, Zoom Level with One Marker
Portable Ruby on Rails Environment
Variable Scope and Order of Parsing VS. Operations: Assignment in an "If"
Rails, Postgresql, and History Triggers
Run Rspec Tasks in a Specific Order
Circular Dependency Detected While Autoloading Constant User
Why Doesn't Minitest::Spec Have a Wont_Raise Assertion
Get Index of String Scan Results in Ruby
How Does Shovel (<<) Operator Work in Ruby Hashes
Strange Inability to Require Config/Boot After Upgrading to Ruby 1.9.2