[regexp] How to convert string "/regexp/i" to /regexp/i -?

When i try to use:

Regexp.new("/regexp/i")
=> //regexp/i/

But it’s not what i want - i need:

/regexp/i

:frowning:

How i can convert this proper way?

2009/8/21 Joao S. [email protected]:

How i can convert this proper way?

Try without the quotes

Regexp.new(/regexp/i)
=> /regexp/i

Cheers,

Joao S. wrote:

:frowning:

How i can convert this proper way?

If that is exactly the kind of string you are expecting, I think you are
stuck with having to use eval.

irb(main):001:0> r = eval("/regexp/i")
=> /regexp/i
irb(main):002:0> r.match(“REGEXP”)
=> #<MatchData “REGEXP”>

If you do not need the options, you could just grab the inner part and
make a regexp out of that:

irb(main):001:0> re = “/som.r.g.x\d+/i”
=> “/som.r.g.xd+/i”
irb(main):002:0> re = “/som.r.g.x\d+/i”.match(//(.*)/[^/]/)[1]
=> “som.r.g.x\d+”
irb(main):003:0> /#{re}/.match(“someregex1123”)
=> #<MatchData “someregex1123”>

Not really a great solution, though, as you lose information.

-Justin

Regexp.new(/regexp/i)

Fleck Jean-Julien wrote:

2009/8/21 Joao S. [email protected]:

How i can convert this proper way?

Try without the quotes

Regexp.new(/regexp/i)
=> /regexp/i

Cheers,

I cannot do this without quotes - i need get it from string. Only thing
i have is “/regexp/i” string.

Thanks!

Justin C. wrote:

/regexp/i
=> /regexp/i
irb(main):003:0> /#{re}/.match(“someregex1123”)
=> #<MatchData “someregex1123”>

Not really a great solution, though, as you lose information.

-Justin

I should add, for the second approach you could also parse the options
and then manually build up the regexp with the corresponding options.
That is the “non-lazy” way, though :slight_smile:

-Justin

Michal Zacik wrote:

Regexp.new(/regexp/i)

? Without “”?

Joao S. [email protected] writes:

Cheers,

I cannot do this without quotes - i need get it from string. Only thing
i have is “/regexp/i” string.

string=“/regexp/i”
Regexp.new(eval(string))

On Fri, Aug 21, 2009 at 12:00 PM, Pascal J.
Bourguignon[email protected] wrote:

=> /regexp/i

Pascal B.

Eval is a mighty tool for a tiny task

option = str[-1] # Ruby 1.9, use [-1,1] in 1.8

Regexp::new( str[1…-3], option )

HTH
R

Pascal J. Bourguignon wrote:

Joao S. [email protected] writes:

Cheers,

I cannot do this without quotes - i need get it from string. Only thing
i have is “/regexp/i” string.

string=“/regexp/i”
Regexp.new(eval(string))

I tried this, but it’s totally unsafe way (these strings are provided by
user).

Joao S. wrote:

When i try to use:

Regexp.new("/regexp/i")
=> //regexp/i/

But it’s not what i want - i need:

/regexp/i

:frowning:

How i can convert this proper way?

str = “/regexp/i”
pieces = str.split("/")
pattern = pieces[1]

my_regex = Regexp.new(pattern, true)

md = my_regex.match(“hello ReGexP”)
puts md[0]

–output:–
ReGexP

Or, more generally:

str = “/reg.*?exp/im”
pieces = str.split("/")
pattern = pieces[1]
flags = pieces[2]

arg_two = 0

flags.length.times do |i|
case flags[i, 1]
when “i”
arg_two |= Regexp::IGNORECASE
when “m”
arg_two |= Regexp::MULTILINE
when “x”
arg_two |= Regexp::EXTENDED
end

end

regex = Regexp.new(pattern, arg_two)

test_str =<<ENDOFSTRING
hello rEG
world exP
ENDOFSTRING

md = regex.match(test_str)
if md
puts md[0]
end

–output:–
rEG
world exP

class String
def to_r
Regexp.new(strip.match(//(.)/(.*)/)[1,2])
end
end

“/regexp/i”.to_r # => /regexp/i

On Fri, Aug 21, 2009 at 4:18 AM, Joao S. <

2009/8/21 Pascal J. Bourguignon [email protected]:

=> /regexp/i

Cheers,

I cannot do this without quotes - i need get it from string. Only thing
i have is “/regexp/i” string.

string=“/regexp/i”
Regexp.new(eval(string))

“Regexp.new” is superfluous:

irb(main):002:0> eval(“/regexp/i”).class
=> Regexp
irb(main):003:0>

Cheers

robert

Josh C. wrote:

class String
def to_r
Regexp.new(strip.match(//(.)/(.*)/)[1,2])
end
end

“/regexp/i”.to_r # => /regexp/i

Doesn’t work in this case:

str = “/reg.*?exp/m”

test_str =<<ENDOFSTRING
hello rEG
world exP
ENDOFSTRING

…nor when there is more than one flag.

On Aug 21, 2009, at 06:04, Joao S. wrote:

I tried this, but it’s totally unsafe way (these strings are
provided by
user).

If the strings are provided by an untrusted source, don’t use any
solution that uses eval().

Instead, use a solution that recognizes the string contains a regexp
and then uses a regexp constructor after pulling the relevant data out
of the string. Something along the lines of:

def parse_input(str)
if md = %r{^/(.)+/(.)*$}.match(str)
#it’s a regexp
pattern = md[1]
if md[2]
# deal with the flags
flags = deal_with(md[2]
end
Regexp.new(pattern, flags)
else

end
end

Ben

Josh C. wrote:

Sorry, it gave me what I expected, and Ruby is usually intuitive, so I
thought I got it right.

Mine solution has problems too–for the same reason. It needs something
like this:

arg_two = nil if arg_two == 0
regex = Regexp.new(pattern, arg_two)

Sorry, it gave me what I expected, and Ruby is usually intuitive, so I
thought I got it right. This class, however, is not. I had to learn some
of
it’s internal logic to figure it out. (they define constants for each
flag,
these constants are integers, you then have to add the values of the
constants of all the flags together to get the new options value)

class String
return nil unless self.strip.match(/\A/(.)/(.)\Z/mx)
regexp , flags = $1 , $2
return nil if !regexp || flags =~ /[^xim]/m

x = /x/.match(flags) && Regexp::EXTENDED
i = /i/.match(flags) && Regexp::IGNORECASE
m = /m/.match(flags) && Regexp::MULTILINE

Regexp.new regexp , [x,i,m].inject(0){|a,f| f ? a+f : a }

end
end

#fail cases
“regexp”.to_r # => nil
“regexp/i”.to_r # => nil
“/regexp/mk”.to_r # => nil
<<-ENDOFSTRING.to_r # => nil
hello rEG
world exP
ENDOFSTRING
“/regexp/mk
hello rEG
world exP”.to_r # => nil

#pass cases
“/reg/”.to_r # => /reg/
" /reg/x ".to_r # => /reg/x
"/reg.?exp/m".to_r # => /reg.?exp/m
“/regexp/x”.to_r # => /regexp/x
“/abc
def
ghi/xi”.to_r # => /abc
# def
# ghi/ix

“//”.to_r # => //
“/abc/i”.to_r # => /abc/i
“/abc/x”.to_r # => /abc/x
“/abc/m”.to_r # => /abc/m
“/abc/ix”.to_r # => /abc/ix
“/abc/im”.to_r # => /abc/mi
“/abc/xm”.to_r # => /abc/mx
“/abc/ixm”.to_r # => /abc/mix
“/abc/mxi”.to_r # => /abc/mix

In the spirit of xkcd: Wisdom of the Ancients here’s a better answer:
to_regexp | RubyGems.org | your community gem host
This gem solves the problem. Source:
Convert a regular expression in a string to a regexp object in ruby - Stack Overflow

Once this gem is installed, you can call String#to_regexp and all is
well.

Something like:

key = “ixm”

x = str.reverse_index(’/’)

v = str[x+1…-1]

o = v.characters.inject(0){ |s,c| b = key.index©; b ? 2**b : 0 }

Regexp.new(str[1…x], o)

Or

eval “%r#{str}”

If safety is a concern you can get Pretty Good™ safety by wrapping it
in
a threaded $SAFE=4. Too bad Ruby doesn’t support %R, then it would
perfectly safe.

Ben G. wrote in post #844686:

If the strings are provided by an untrusted source, don’t use any
solution that uses eval().

Yes.

Instead, use a solution that recognizes the string contains a regexp
and then uses a regexp constructor after pulling the relevant data out
of the string. Something along the lines of:

def parse_input(str)
if md = %r{^/(.)+/(.)*$}.match(str)

Nice try, but that regexp isn’t safe. I think Ruby’s design decision
here was a bad one. In Ruby, you need \A to match only at the start of
string, and \z to match only at the end of string (whereas you might
expect ^ and $ to mean that)

Also, I’d suggest that repeated capture groups are a bit confusing, e.g.
where you write (.)+ when (.) by itself would be fine. Because * is
greedy, .* will capture as much as possible so the + will only repeat
once.

Anyway, here’s a trick for handling the flags: note that /foo/i can be
represented as (?i:foo)

raise "Invalid regexp" unless %r{\A/(.*)/([mix]*)\z} =~ str
Regexp.new("(?#{$2}:#{$1})")