3

Using Ruby 1.8.7 I want to store some regular expressions in the database and have them be easily reconstituted as a Regexp object when I need to use them for validation. I've found that Ruby exhibits some unwanted behavior. For instance:

r = Regexp.new(/^\w+$/i)        => /^\w+$/i
r_i = r.inspect                 => "/^\\w+$/i"
r_s = r.to_s                    => "(?i-mx:^\\w+$)"
r_from_r_i = Regexp.new(r_i)    => /\/^\w+$\/i/
r_from_r_s = Regexp.new(r_s)    => /(?i-mx:^\w+$)/
r == r_from_r_i                 => false
r == r_from_r_s                 => false

What I'd like is to be able to store the Regexp in the database in the form /pattern/options instead of the (?options:pattern) format, because I'm more familiar with the former. But, when creating a new Regexp from a variable, the pattern gets all wacky. Ruby is escaping the /s - so the pattern is invalid.

Is there any way to make Ruby honor the /pattern/options format when parsing a regular expression?

Arup Rakshit
  • 109,389
  • 25
  • 234
  • 293
Josh M.
  • 23,573
  • 23
  • 96
  • 160
  • 1
    Really, what's wrong with `r_s`? It doesn't compare as equal the original, but it behaves exactly the same. – John Dvorak Feb 16 '14 at 05:54
  • @JanDvorak You are right! – Arup Rakshit Feb 16 '14 at 06:32
  • The real problem here is highlighted by my updated example above. When loading a regex from a string variable, the `/`s are escaped when I just want the `Regexp` object to parse my pattern and string as-is. – Josh M. Feb 16 '14 at 20:14
  • Please don't change the question, after so many hours, which made my effort completely vague now. Please rollback your edit. Create a new post, we will help you there. – Arup Rakshit Feb 16 '14 at 20:25

1 Answers1

8

You can do as below:

r = Regexp.new(/^\w+$/i) # => /^\w+$/i
source,option = r.source,r.options # => ["^\\w+$", 1]
regex = Regexp.new(source,option)
regex == r # => true

options

Returns the set of bits corresponding to the options used when creating this Regexp

source

Returns the original string of the pattern

Now, if you want a single variable to hold all your Regex details, then consider as below:

r = Regexp.new(/^\w+$/i) # => /^\w+$/i
source_option = r.source,r.options # => ["^\\w+$", 1]
regex = Regexp.new(*source_option)
regex == r # => true

Why did yours get false with to_s or inspect?

Read the doc carefully; you can see that Regexp.to_s is saying:

Returns a string containing the regular expression and its options (using the (?opts:source) notation. This string can be fed back in to Regexp::new to a regular expression with the same semantics as the original. (However, Regexp#== may not return true when comparing the two, as the source of the regular expression itself may differ, as the example shows). Regexp#inspect produces a generally more readable version of rxp.

Now, see:

r = Regexp.new(/^\w+$/i) # => /^\w+$/i
r_s = r.to_s
r_from_r_s = Regexp.new(r_s)
r == r_from_r_s # => false
# because the source strings are not same for r and r_from_r_s
r.source # => "^\\w+$"
r_from_r_s.source # => "(?i-mx:^\\w+$)"

The same explanation as above holds for the result of r == r_from_r_i.

sawa
  • 156,411
  • 36
  • 254
  • 350
Arup Rakshit
  • 109,389
  • 25
  • 234
  • 293
  • Thanks for your answer, but I think I was unclear when I posted the original problem - it was late at night. The issue is with loading a regex from a string - see my updated question and let me know if there's anyway to make the Regexp object parse my complete regex in the form `/pattern/options`. Thanks! – Josh M. Feb 16 '14 at 20:15
  • @JoshM. Please don't change the question, after so many hours, which made my effort completely vague now. Please rollback your edit. Create a new post, we will help you there. – Arup Rakshit Feb 16 '14 at 20:18
  • @JoshM. May be for you. For us, what we understand from your examples, tried to clarify that. So, now if you think, you need more help towards your problem, create another post, by putting a specific doubts.. – Arup Rakshit Feb 16 '14 at 20:46