SFLEX has asked for the wisdom of the Perl Monks concerning the following question:

A code I have made that needs to have "use re 'eval'" and from what the perl manual says for "use re 'eval'" will disable security in the regex.
I do not want to disable the security if i do not need to so i made a code the gets around the runtime error. In the file Iv been testing the logic of how its going to work, has a few strange bugs in it and it seems to be the "use re 'eval'" code that does some of them.
The Example 6 code i made works and I'm guessing is less buggy then the "use re 'eval'" code(Example 5). But Example 6 just looks to big to me and would like to know how to do it another way(thats stable).
In the code i have comments to explain how i want it to work, i hope....
Keep in mined I'm testing this on "v5.8.8 built for MSWin32-x86-multi-thread, Binary build 817 ActiveState"
I made this post to know if there is another way and for others to review if this is a Perl bug.
#!/usr/bin/perl use strict; use warnings; my %Build = ( jj => '0-9', ); # Example 5 does not like this and i need the code to handle more then + 1 # my %Build = ( # jj => '0-9', # kk => 'a-z', # ); my $message = '[445] [5353453] [fff] [445]'; my $message2 = $message; my $message3 = $message; my $message4 = $message; my $message5 = $message; my $message6 = $message; # jump to Example 1, It should make more sense then # Example 6 # This is the code i made to get around these problems # what is strange about this file is if this code is last it did not w +ork # Look for "# Not Here" for the location it does not work at # Also this looks to me to be to big and the size of Example 5 looks b +etter # but i don t like having "use re 'eval';" because it seems to produce + bugs in this file # and if it does it in this file, I don t want to use it. # is there another way? foreach my $b_key2 (keys %Build) { my @re_match = (); @re_match = ($message6 =~ m{\[([$Build{$b_key2}]+)\]} +isg); my %speed_fix = (); if (@re_match) { foreach my $m_check (@re_match) { next if $speed_fix{$m_check}; my $built = ''; $built = return_number($m_check); if ($built) { $message6 =~ s{\[([$m_check]+)\]}{$built}isg; $speed_fix{$m_check} = 1; } } } } # Example 1 # the first test # but needs to be in a foreach and inside (?{ code }) will call a sub $message =~ s{\[([0-9]+)\](?(?{$+ ne ''})|(?!))}{$+}gs; # Example 2 # this calls a sub but removes what it matched my $vid = ''; $message2 =~ s{\[([0-9]+)\](?(?{ $vid = return_number($+); $vid ne '' +})|(?!))}{$vid}gs; # if a space was added it returns the match $vid = ''; # Example 3 $message3 =~ s{\[([0-9]+)\](?(?{ $vid = return_number($+); $vid ne '' +})|(?!))}{$vid }gs; # space here # Example 4 # the start of what i wanted to do but has an error so its commented o +ut # # Error: Eval-group not allowed at runtime, use re 'eval' # foreach my $b_key (keys %Build) { # my $vid = ''; # $message4 =~ s{\[([$Build{$b_key}]+)\](?(?{$vid = $1; $v +id ne ''})|(?!))}{$vid}gs; # } # Example 5 # With use re 'eval'; # almost works but has a few bugs and causes a bug in Example 6. # if Example 6 was under comment "# Not Here" then Example 6 will not +work # Next Jump to Example 6 at the top foreach my $b_key (keys %Build) { my $re_pat = '(?(?{my $vid = return_number($+); $vid ne \' +\'})|(?!))'; use re 'eval'; $message5 =~ s{\[([$Build{$b_key}]+)\]${re_pat}}{$vid}gs; no re 'eval'; } # Not Here print "Content-type: text/html\n\n"; print "<html><h1>Example 1: $message,<br> Example 2: $message2,<br> Ex +ample 3: $message3,<br> Example 4: $message4,<br> Example 5: $message +5,<br> Example 6: $message6</h1></html>\n"; sub return_number { my $numbers = shift; return $numbers; }

Update:i want to take a hash of simple regex ie(0-9, a-z) and match them in square brackets/box brackets: /\[([0-9]+)\]/;
The matched value in the brackets then gets checked from a sub(to make it simple i have it go though the sub) and if the sub returns something it uses the value the sub returned and if the sub did not return anything it keep the data as it was

Replies are listed 'Best First'.
Re: Regex (?{ code }) and use re 'eval'
by ikegami (Patriarch) on Nov 21, 2007 at 18:09 UTC

    If the regex is built from untrusted input, the consider these words from Nicholas Clark (talking about another issue):

    So it's not going to be an issue at all, unless your programmers are foolish enough to allow untrusted user input to be interpolated into regular expressions. In which case, you were already open to denial of service attacks from patterns that bust the C stack (fixed by Dave for 5.10) or take until the heat death of the universe to complete (inherently unfixable in a general purpose programming language)

    If the regex is built from trusted input, then use re 'eval'; won't hurt.

    would like to know how to do it another way(thats stable).

    Do what? You didn't say what it's suppose to do. There's not a single comment that hints as to what it's suppose to do. Yet we're suppose to figure out what you want from complex code that "has a few strange bugs in it".

      Sorry, maybe this will help you out.

      i want to take a hash of simple regex ie(0-9, a-z) and match them in square brackets/box brackets: /\[([0-9]+)\]/;
      The matched value in the brackets then gets checked from a sub(to make it simple i have it go though the sub) and if the sub returns something it uses the value the sub returned and if the sub did not return anything it keep the data as it was

        I won't claim to clearly understand what you are doing but it looks like using (?{...}) is an overly complex way to go here. Something much simpler might work for you:

        s/(...)/ func( $1 ) || $1 /ge; s/(\[(...)\])/ func( $2 ) || $1 /ge; s/(\[(...)\])/ my $ret= func( $2 ); defined $ret ? "[$ret]" : $1 /ge; s/(\[(...)\])/ my @ret= func( $2 ); @ret ? "[@ret]" : $1; /ge;

        - tye        

        i want to take a hash of simple regex ie(0-9, a-z) and match them in square brackets/box brackets

        Under these conditions, your "example 6" would look sth. like:

        use strict; use warnings; my %Build = ( jj => '0-9', kk => 'a-z', ); my $message = '[445] [5353453] [fff] [445]'; my $message6 = $message; while( my ($k,$v) = each %Build) { my %speed_fix; if(my @re_match = $message6 =~ m{ (?<=\[) [$v]+ (?=\]) }xisg ) { foreach my $m_check (@re_match) { next if $speed_fix{$m_check}; if( my $built = return_number($m_check) ) { $message6 =~ s{ \[ $m_check \] }{$built}xisg; ++$speed_fix{$m_check}; } } } } print "$message6\n"; sub return_number { my $numbers = shift; return $numbers; }

        Maybe one could delete more stuff - if you could provide an exact specification of the problem.

        Regards

        mwa

        What do you mean by "returns something"? I'm going to assume you mean "returns something defined". Adjust as needed.

        foreach my $range (values %Build) { $message =~ s{ (\[ ([$range]+) \]) }{ my $val = return_number("$2"); defined($val) ? $val : $1 }exig }

        If return_number is costly, you can memoize the returned value.

        my %memoize; foreach my $range (values %Build) { $message =~ s{ (\[ ([$range]+) \]) }{ my $val = exists($memoize{$2}) ? $memoize{$2} : return_number("$ +2"); $memoize{$2} = $val; defined($val) ? $val : $1 }exig }

        Why is Build a hash instead of an array? You don't use the keys. Also, Build is not a particularly good name.