=~ and rescue

P

Patrick Gundlach

Dear Ruby-Hackers,

i'd like to catch a malformed regular expression like this:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#!/usr/bin/ruby

begin
"abcd" =~ /*foo*/
rescue StandardError
puts "error"
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


The above does not work (-:4: invalid regular expression; there's no
previous pattern, to which '*' would define cardinality at 1: /*foo*/)

How do I catch this correctly?

Patrick
 
J

Jason Williams

Dear Ruby-Hackers,

i'd like to catch a malformed regular expression like this:
"abcd" =~ /*foo*/
rescue StandardError
puts "error"
end

Why would you want to do that? Its an error that can be caught
at compile-time, so why let it go until run-time? You can fool
it into missing the error like this, if you want -

regexString = "*foo*"
begin
"abcd" =~ /#{regexString}/
rescue RegexpError
puts "Oops"
end

....but I don't see what this gains.
 
P

Patrick Gundlach

Hi,
Why would you want to do that? Its an error that can be caught
at compile-time, so why let it go until run-time?

Because I want to let a user create a regexp and use it in /../.

You can fool it into missing the error like this, if you want -

[....]

great!

Thank you very much.

BTW: Is there something like a generic Error that can be used with
rescue?

Like

begin
something bad
rescue anyerror
recover
end

Patrick
 
H

henon

Patrick Gundlach wrote:

[...]
BTW: Is there something like a generic Error that can be used with
rescue?

the superclass of all exceptions is Exception.

so:

begin
...
rescue Exception
end

will definitely catch any exceptions thrown between begin and end.

-- henon
 
H

henon

Patrick Gundlach wrote:
[...]
I guess it is just rescue without any parameter?

No, that rescues just StandardError

also, if you get regexp input from your users be aware of the fact,
that a regexp may execute ruby code:

this is a regexp that prints Hello World!

/#{puts 'Hello World!'}/

cheers,
- henon
 
P

Patrick Gundlach

Hi,

henon said:
No, that rescues just StandardError

good to know. Next time I should read the pickaxe more carefully.
also, if you get regexp input from your users be aware of the fact,
that a regexp may execute ruby code:

this is a regexp that prints Hello World!

/#{puts 'Hello World!'}/

Oh no! Is there any simple way to circumvent this? Or do I have to
analyze (strip #{...} from) the regexp?

Thank you for the important hint.

Patrick
 
R

Robert Klemme

Patrick Gundlach said:
Hi,


Because I want to let a user create a regexp and use it in /../.

But then I'd use Regexp.new:

user_regexp = get_input()

begin
rx = Regexp.new( user_regexp, user_set_flags )
rescue RegexpError => e
user_feedback( e )
end

Regards

robert
 
P

Patrick Gundlach

Hello again,

henon said:
also, if you get regexp input from your users be aware of the fact,
that a regexp may execute ruby code:

this is a regexp that prints Hello World!

/#{puts 'Hello World!'}/

But not in this case:

--------------------------------------------------
#!/usr/bin/ruby

malcode="#" + "{ puts 'hallo' }"

puts malcode # prints #{ puts 'hallo' }

"foo" =~ /#{malcode}/ # does not print anything
 
P

Patrick Gundlach

Hello Robert,


Robert Klemme said:
But then I'd use Regexp.new:

user_regexp = get_input()

begin
rx = Regexp.new( user_regexp, user_set_flags )
rescue RegexpError => e
user_feedback( e )
end

I now have

begin
do_something if mystring =~ user_regexp
rescue ....
user_feedback ...
end

what is the advantage of Regexp.new over my approach?

Patrick
 
R

Robert Klemme

Patrick Gundlach said:
Hello Robert,




I now have

begin
do_something if mystring =~ user_regexp
rescue ....
user_feedback ...
end

what is the advantage of Regexp.new over my approach?

irb(main):003:0> "foo" =~ "fo+"
(irb):3: warning: string =~ string will be obsolete; use explicit regexp
=> 0
irb(main):004:0>

IOW, "mystring =~ user_regexp" is not a regexp match if "user_regexp" is
not a regexp string and in future versions it will be only a string match
regardless what kind of string is there in user_regexp.

Regexp.new() is simply the directest way to create a regexp from a string
and also it's faster:

09:23:49 [ruby]: ruby rx-eval.rb
user system total real
eval 2.125000 0.000000 2.125000 ( 2.133000)
direct 1.515000 0.015000 1.530000 ( 1.558000)
09:24:14 [ruby]: cat rx-eval.rb

require 'Benchmark'
include Benchmark

REP = 100000
expr = "fo+"
eval_expr = "/#{expr}/"

bm do |run|
run.report( "eval" ) do
for i in 0...REP
eval eval_expr
end
end

run.report( "direct" ) do
for i in 0...REP
Regexp.new expr
end
end

end
09:24:34 [ruby]:

Cheers

robert
 
P

Patrick Gundlach

Hello Robert,


Robert Klemme said:
IOW, "mystring =~ user_regexp" is not a regexp match if "user_regexp" is
not a regexp string and in future versions it will be only a string match
regardless what kind of string is there in user_regexp.

OK, thank you for then enlightenment.
Regexp.new() is simply the directest way to create a regexp from a string
and also it's faster:

That is interesting, too! And I didn't know of Benchmark yet. Thanks
again.

Patrick
 
P

Patrick Gundlach

Hi again,

does anybody have an insight of this?
But not in this case:

--------------------------------------------------
#!/usr/bin/ruby

malcode="#" + "{ puts 'hallo' }"

puts malcode # prints #{ puts 'hallo' }

"foo" =~ /#{malcode}/ # does not print anything


Patrick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,138
Messages
2,570,804
Members
47,349
Latest member
jojonoy597

Latest Threads

Top