Reputation: 321
Is it possible to concat two regex variables in Ruby?
r1 = /my_str/
r2 = /my_str1/
r3 = r1+r2
Can anyone give any suggestions?
Upvotes: 15
Views: 7967
Reputation: 51053
Contra other answers, it's not strictly necessary to call source
; in many cases Regexp#to_s
works just as well. From the docs:
Returns a string containing the regular expression and its options (using the
?(opts:source)
notation. This string can be fed back in to ::new to a regular expression with the same semantics as the original.
So often it's enough to just use string interpolation:
r1 = /my_str1/
# => /my_str1/
r2 = /my_str2/
# => /my_str2/
r3 = Regexp.new("#{r1}|#{r2}")
# => /(?-mix:my_str1)|(?-mix:my_str2)/
The result is less readable than the /my_str1|my_str2/
, but will match identically -- the tradeoff is more readable source for a less readable regexp.
That said, if you want to apply different options to the combined expression (or parts of it) than to the original expressions, you will need to call source
.
r1 = /[a-z]\n[0-9]/
r2 = /[0-9]\n[a-z]/
r3 = Regexp.new("(?mi-x:(#{r1.source}|#{r2.source}))")
# => /(?mi-x:([a-z]\n[0-9]|[0-9]\n[a-z]))/
r3.match("A\n1")
# => #<MatchData "A\n1" 1:"A\n1"> <-- works
r4 = Regexp.new("(?mi-x:(#{r1}|#{r2}))")
# => /(?mi-x:((?-mix:[a-z]\n[0-9])|(?-mix:[0-9]\n[a-z])))/
r4.match("A\n1")
# => nil <-- doesn't work b/c wrong options
Upvotes: 4
Reputation: 23782
Concatenate the source
s and pass to Regexp.new
:
2.4.1 :009 > r1 = /a./
=> /a./
2.4.1 :010 > r2 = /b{3}/
=> /b{3}/
2.4.1 :011 > r3 = Regexp.new(r1.source + r2.source)
=> /a.b{3}/
2.4.1 :022 > "axbbb" =~ r3
=> 0
2.4.1 :023 > "axbb" =~ r3
=> nil
Upvotes: 12
Reputation: 288
Following works in Ruby - but I think it's not beautiful:
2.5.3 :001 > r1 = /my_str1/
=> /my_str/
2.5.3 :002 > r2 = /my_str2/
=> /my_str1/
2.5.3 :003 > r3 = Regexp.new( "#{r1.source}|#{r2.source}" )
=> /my_str1|my_str2/
Of course you even could implement + on Regexp yourself, like this (but of course totally not recommended ^^):
class Regexp
def +(regexp)
self.class.new("#{source}|#{regexp.source}")
end
end
Then you can do:
2.5.3 :004 > class Regexp
2.5.3 :005?> def +(regexp)
2.5.3 :006?> self.class.new("#{source}|#{regexp.source}")
2.5.3 :007?> end
2.5.3 :008?> end
=> :+
2.5.3 :009 > r1 + r2
=> /my_str1|my_str2/
There are of course reasons, why this is not implemented. I just assumed a or as concatenation (that should at least work in any cases - even when as mostly it's recommended definite start and end are defined in Regexp). But most probable you have some very different use case. So when you want to concatenate in different way, you maybe have to ensure that in first regexp \Z
and in second \A
has to be removed...
Upvotes: 1
Reputation: 374
If you have two regular expression , you can concatenate them like this:
var r1 = /my_str/;
var r2 = /my_str1/;
var r3 = new RegExp( r1.source + r2.source );
Upvotes: -1