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

Hi,

I'm frustrate because I cannot imagine which makes in my code fails next sentence (which works fine until some points which I don't know):

if ($r =~ //) { xxx }

I was debugging my issue and find this, maybe there is relation:

Consider next simple program:

#!/usr/bin/perl -w use CGI qw(:standard); my $q=CGI->new ;
And then execute perl -d file or perl -e perl -d -e 'use CGI qw(:standard); $q=CGI->new' Then in the debugger:
DB<1> w print "hola" if ("r" =~ //); DB<2> holac Watchpoint 0: print "hola" if ("r" =~ //); changed: old value: '1' new value: '' CGI::_compile(/usr/share/perl/5.12/CGI.pm:867): 867: ($pack,$func_name) = ($1,$2); DB<2> holaholaholaholaholaholaholaholaholaholaholaholaholaholaholaho +laholaholaholaholaholaholaholaholaholaholaholaholaholaholaholaholahol +aholaholaholaholaholaholaholaholahola DB<2> p print "hola" if ("r" =~ //); DB<3>

So, why "r" =~ // changes her semantics? (note DB<2> response and remember that it happens too in some moment inside my code (which is larger and I cannot post fully here))

Please see that "r" =~ // come from "$r" =~ /$r2/ in my real program. And too if I change $r2 to "." if it is empty my program works fine.

So, do you think I should report it as an CGI.pm bug or do you have any tip for me?

Thank you very much monks!

PD: I don't know if this go better to "Meditations" or it is ok in Seekers section.

Replies are listed 'Best First'.
Re: Is this a bug ?
by chromatic (Archbishop) on Jul 12, 2011 at 19:08 UTC

    From perlop:

    If the PATTERN evaluates to the empty string, the last successfully matched regular expression is used instead.

    This isn't obvious (or often useful) behavior, but it's documented behavior. You can subvert this with a regex assertion such as a comment:

    if ($r =~ /(?#avoid empty pattern)$r2/) { ... }

    It's not a CGI bug. It's an insufficient encapsulation bug with regard to Perl 5 itself.

      Is (?#...) recent? Alternatives:

      /(?:)$pat/ /(?:$pat)/ my $re = qr/$pat/; /$re/

        I'd always used (?:) before, but I'd forgotten how to spell it and found (?#) in the Perl 5.14 documentation. I couldn't find it in a modern perldelta though.

      Hi,

      Now I have the code here, and I tried to apply another logical solution (your solution works!), but it don't work, do you know where is my fail now ?

      My original code was:

      sub casa_ruta { my ($r, $ruta,$exactly)=@_; # avoid empty patern # if (length ($ruta) == 0) # { # $ruta="."; # } if (defined $exactly) { if ($r eq $ruta) { return 1; } } else { if ($r =~ /$ruta/i) { return 1; } } return 0; }
      Then, after reading your comment and manual I propose next solution:
      sub casa_ruta { my ($r, $ruta,$exactly)=@_; if ("r" =~ /(r)/) { ; } else { print STDERR "BUG\n"; } #print STDERR "$fix_re"; # if (length ($ruta) == 0) # { # $ruta="."; # } if (defined $exactly) { if ($r eq $ruta) { return 1; } } else { if ("r" =~ /(r)/) { ; } else { print STDERR "BUG2\n"; } if ($r =~ /$ruta/i) { return 1; } else { printf STDERR "BUG ('$r','$ruta')\n"; printf STDERR join (",",caller); exit 1; } } return 0; }

      But It print in STDERR :

      BUG ('/my/path','')

      My::Module,/path/to/myfile.pm,1181

      and exits

      Effectively with /(?:)$ruta/i it is working ... but I would like to understand this issue

      UPDATE:

      See my next debug trace:

      DB<1> c 152 ... #my script output here main::ejecutar_sae_appfinder(/srv/www/sae_appfinder/index.pl:152): 152: %nodos_tomcats=buscar_ruta_tomcats ($p_ruta,\%apaches, +\%tomcats,$search_tomcathost); DB<2> s Sae::Inventario::buscar_ruta_tomcats(/opt/scripts/perl/Sae/Inventario. +pm:1181): 1181: my ($ruta,$apaches,$tomcats,$search_tomcathost)=@_; DB<2> c casar_ruta Subroutine Sae::Inventario::casar_ruta not found. DB<3> c casa_ruta Sae::Inventario::casa_ruta(/opt/scripts/perl/Sae/Inventario.pm:91): 91: my ($r, $ruta,$exactly)=@_; DB<4> x @_ 0 '' 1 '' DB<5> n Sae::Inventario::casa_ruta(/opt/scripts/perl/Sae/Inventario.pm:94): 94: if ("r" =~ /(r)/) 95: { DB<5> p "$r" =~ /$ruta/ 1<label><input type="radio" name="format" value="html" checked="checke +d" />html</label><label><input type="radio" name="format" value="odt" + />odt</label><br><input type="submit" name="consultar" value="consul +tar" /><div><input type="hidden" name=".cgifields" value="info" /><i +nput type="hidden" name=".cgifields" value="format" /><input type="h +idden" name=".cgifields" value="entorno" /></div></form></div> DB<6> p "$r" =~ /$ruta/ 1 DB<7> n Sae::Inventario::casa_ruta(/opt/scripts/perl/Sae/Inventario.pm:108): 108: if (defined $exactly) 109: { DB<7> p "$r" =~ /$ruta/ DB<8>

      In DB<5> html code is printed here (If I add in the begin of script "$|=1;" it doesn't appear If I understand TFM "r" =~ /(r)/ should make $xx =~ // return true, isn't it?

      See null reply in DB<7> which is different than 1 in DB<6>
      Thanks!
        ok, so I reread the doc, and I understand it. With my proposed solution, i was using "/(r)/" pattern, so it was not working.
        It is not very intuitive, but it is ok
        Sorry wasting your time and a big thank for you
Re: Is this a bug ?
by Anonymous Monk on Jul 12, 2011 at 18:31 UTC

    So, do you think I should report it as an CGI.pm bug or do you have any tip for me?

    Upgrade to CGI.pm 3.55

    Maybe explain how this bug is a problem, preferably without the debugger

      In my code was:
      sub xx { my ($a,$b)=@_; # some sentences later if ($b =~ /$a/) { ... } }
      I tried to explain with my sentence:
      Please see that "r" =~ // come from "$r" =~ /$r2/ in my real program. And too if I change $r2 to "." if it is empty my program works fine.
      I had to use debugger to know what was happened ..

      chromatic had the answer !!

      Thank you very much, I will use "m//"