Swapnil
Swapnil

Reputation: 321

Is it possible to concat two regex variables?

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

Answers (5)

David Moles
David Moles

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

Pistos
Pistos

Reputation: 23782

Concatenate the sources 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

steenslag
steenslag

Reputation: 80065

Regexp::union

r1 = /my_str/
r2 = /my_str1/
r3 = Regexp.union(r1, r2)

Upvotes: 10

bpieck
bpieck

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 \Zand in second \A has to be removed...

Upvotes: 1

Dasrath
Dasrath

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

Related Questions