Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Identifying if a variable is the product of a qr//

by demerphq (Chancellor)
on Apr 25, 2002 at 09:49 UTC ( [id://161902]=perlquestion: print w/replies, xml ) Need Help??

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

Yesterday broquaint and I were chatting and he mentioned a code snippet like this
sub blessed_regex{ return bless qr/[a-z]/,'foo' }
To which I replied (stupidly) that that wouldnt work, the product of qr// is just a blessed scalar that happens to stringify itself as the regular expression it contains, and that reblessing would destroy the magic. So that it would have to be like this
sub blessed_regex{ return bless \qr/[a-z]/,'foo' }

Well I was wrong! as the code below shows.
use strict; use warnings; use Data::Dumper; my $rex = qr/[A-Z]o[A-Z]/; my $blessed = bless qr/[A-Z]o[A-Z]/,'foo'; $\="\n"; $,=":\t"; print "Rex ",ref $rex; print "Bless",ref $blessed; print "Rex ",$rex,"WoW"=~$rex ? "WoW" : "---"; print "Bless",$blessed,"WoW"=~$blessed ? "WoW" : "---"; print "Rex ",$rex,"wow"=~$rex ? "!WoW" : "---"; print "Bless",$blessed,"wow"=~$blessed ? "!WoW" : "---"; print "Rex ",Dumper($rex); print "Bless",Dumper($blessed); __END__ Rex : Regexp Bless: foo Rex : (?-xism:[A-Z]o[A-Z]): WoW Bless: foo=SCALAR(0x1a7ef64): WoW Rex : (?-xism:[A-Z]o[A-Z]): --- Bless: foo=SCALAR(0x1a7ef64): --- Rex : $VAR1 = qr/(?-xism:[A-Z]o[A-Z])/; Bless: $VAR1 = bless( do{\(my $o = undef)}, 'foo' );
So, the blessed version seems to match correctly, but when stringified returns the stringification of a scalar ref. And Dumper doesnt handle it correctly.

As far as I cant tell from the above results precompiled regexes are in fact base types from the POV of the perl programmer, like real scalars, arrays or hashes or globs. (Actually im sure that the subject of perls types could fill an entire meditiation or five :-) And as far as I can tell there is _no_way_ to determine whether a scalar reference is actually a reference to a real scalar or to a regex.

Can anybody tell me if im wrong, and if so how do I differentiate

bless \"foo","foo"
from
bless qr/somepattern/,"foo";

Many thanks,

Yves / DeMerphq
---
Writing a good benchmark isnt as easy as it might look.

Replies are listed 'Best First'.
Re: Identifying if a variable is the product of a qr//
by demerphq (Chancellor) on Apr 25, 2002 at 10:13 UTC
    One thing I left out. The reason Dumper is printing out the blessed qr// as \undef is becuase it sees it as a reference to a scalar (which apparently it is, but isnt really (whee perl is fun! :-)) and tries to follow it using $$var. But $$var seems to evaluate to undef in this situation (apparently another hole in the way the regex type is handled) so Dumper ends up rendering it as a reference to a var. It is precisely this reason that I want to know how to identify these beasties. My dumper should handle this situation properly.

    $ $\=$/; my $var=bless qr/[A-Z]o[A-Z]/,'foo'; print $var; print ref $var; print defined $$var ? $$var : 'undef';

    Yves / DeMerphq
    ---
    Writing a good benchmark isnt as easy as it might look.

Re: Identifying if a variable is the product of a qr//
by JayBonci (Curate) on Apr 25, 2002 at 10:59 UTC
    So I'll take a stab at this, and maybe I'm missing what you're asking.

    If you bless in a regular expression, it becomes a SCALAR, and as far as I can tell, there's no way to come up with the direct reference of it again, without putting it into regular expression context, like you have (but the only way I can see to do that is to actually use it). Then perl's internal magic kicks in, and blammo, it works.

    However, this code below, works to determine whether a blessed thingy is a regexp:
    #!/usr/bin/perl -w use strict; use warnings; use Data::Dumper; my $rex = qr/[A-Z]o[A-Z]/; my $bar = \$rex; #my $blessed = bless qr/[A-Z]o[A-Z]/,'foo'; my $blessed = bless $bar, 'foo'; $\="\n"; $,=":\t"; print "Rex ",ref $rex; print "Bless",ref $blessed; print "Rex ",$rex,"WoW"=~$rex ? "WoW" : "---"; print "Bless",$blessed,"WoW"=~$$blessed ? "WoW" : "---"; print "Rex ",$rex,"wow"=~$rex ? "!WoW" : "---"; print "Bless",$blessed,"wow"=~$$blessed ? "!WoW" : "---"; print "Rex ",Dumper($rex); print "Bless",Dumper($blessed); print "Blessed bar", ref $$blessed;
    lends me back:
    Rex : Regexp Bless: foo Rex : (?-xism:[A-Z]o[A-Z]): WoW Bless: foo=SCALAR(0x80fd428): WoW Rex : (?-xism:[A-Z]o[A-Z]): --- Bless: foo=SCALAR(0x80fd428): --- Rex : $VAR1 = qr/(?-xism:[A-Z]o[A-Z])/; Bless: $VAR1 = bless( do{\(my $o = qr/(?-xism:[A-Z]o[A-Z])/)}, 'foo' +); Blessed bar: Regexp


    So you can work around it, by blessing references to references in, thus making the internal reference type of 'ref' and then maybe you don't have that layer of blessed magic-ness to work around. Is it because there is no way to put a scalar in regexp context without actually running it?

        --jb
Re: Identifying if a variable is the product of a qr//
by broquaint (Abbot) on Apr 25, 2002 at 11:07 UTC
    I think the problem is that Regexp isn't yet a consolidated type. It is technically a bless()ed reference to the mystical Regexp package, but there's also some magic going on behind the scenes (as demonstrated in Juerd's node above). So it can and will behave like a base type, but also has the power of being bless()ed (are these the first steps towards a more Ruby-like language? ;-). See here for a nice summary on the discussion of what a Regexp really is.
    HTH

    _________
    broquaint

Re: Identifying if a variable is the product of a qr//
by Juerd (Abbot) on Apr 25, 2002 at 10:46 UTC

    This is ugly, but it works. (For 99.9% of all cases - if you are able to predict a scalar reference's stringification, this will fail. :)

    sub is_qr { my ($qr) = @_; return 0 unless ref $qr; return 0 if defined $$qr; # Update: added this line. return 1 if ref $qr eq 'Regexp'; return index(qr/$qr/, "$qr") == -1; }
    This assumes that everything blessed into Regexp is a qr//, but if you don't trust that, just remove the "return 1" line.

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

Re: Identifying if a variable is the product of a qr//
by Juerd (Abbot) on Apr 25, 2002 at 10:13 UTC

    It doesn't matter. As soon as you bless it into another package, it is no longer a precompiled regex, but a reference to an undefined scalar (Dumper isn't handling this incorrectly, the scalar actually is undef).

    This is normal behaviour. If $object is blessed into Foo, and you re-bless it into Bar, it is no longer an object of class Foo.

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

      As soon as you bless it into another package, it is no longer a precompiled regex,but a reference to an undefined scalar (Dumper isn't handling this incorrectly, the scalar actually is undef).

      Er, no (although thats what I thought at first too, run the code I provided.) It still is a precompiled regex otherwise it wouldn't match as it did in my example code.

      This is normal behaviour. If $object is blessed into Foo, and you re-bless it into Bar, it is no longer an object of class Foo.

      The results that I got in the code I posted suggest that in fact a regex is a base type like array or hash and thus its underlying behaviour does not change as it is blessed and reblessed.

      Oh and it gets weirder, there is no way using UNIVERSAL::isa() to determine if a blessed scalar ref is a regex.

      Yves / DeMerphq
      ---
      Writing a good benchmark isnt as easy as it might look.

        although thats what I thought at first too, run the code I provided.

        Did run it, but didn't notice the scalar ref matching correctly.

        Using Devel::Peek, you can clearly see there is something MAGICal going on, maybe it helps...

        2;1 juerd@ouranos:~$ cat dm use Devel::Peek; print Dump bless qr/foo/, 'foo'; print Dump bless \my $foo, 'foo'; 2;0 juerd@ouranos:~$ perl dm SV = RV(0x810b404) at 0x80f60ac REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x80f61a8 SV = PVMG(0x8101b30) at 0x80f61a8 REFCNT = 1 FLAGS = (OBJECT,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x80fffe0 MG_VIRTUAL = 0x80f4f74 MG_TYPE = 'r' MG_OBJ = 0x8100160 STASH = 0x80fd414 "foo" SV = RV(0x810b404) at 0x80f60ac REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x80fd450 SV = PVMG(0x8101b30) at 0x80fd450 REFCNT = 2 FLAGS = (PADBUSY,PADMY,OBJECT) IV = 0 NV = 0 PV = 0 STASH = 0x80fd414 "foo"

        - Yes, I reinvent wheels.
        - Spam: Visit eurotraQ.
        

Re: Identifying if a variable is the product of a qr//
by demerphq (Chancellor) on Apr 25, 2002 at 14:04 UTC
    I got an interesting response about this subject from Rafael Garcia-Suarez about this, he said it was ok to post it so here goes...
      You can mess with the internals : something like
      use B qw/class svref_2object/; sub is_a_precompiled_regexp { my $r = shift; return 0 unless ref $r; my $o = svref_2object $r; return (class($o) eq "PVMG") && ($o->MAGIC->TYPE eq 'r') ? 1 : 0; }
      Without looking at the internals, I don't have an answer.
    Thanks Rafael!

    Yves / DeMerphq
    ---
    Writing a good benchmark isnt as easy as it might look.

Re: Identifying if a variable is the product of a qr//
by Rhandom (Curate) on Apr 25, 2002 at 15:28 UTC
    The following code throws some light:
    perl -e '$qr = "[A-Z]o[A-Z]"; print "[".("WoW" =~ $qr)."][".("wow" =~ +$qr)."]\n";' # prints [1][]


    Any string in perl really can be a regular expression. The binding operator allows you to use just about anything that stringifies as a regular expression. That being said, there really isn't anything magical about the Regexp class except that its objects are able to stringify with the appropriate regexp. That basically means, that unless the object is blessed into the Regexp class, there really is no way to know if the object is intended for Regexp use or not. And even if it is not - that doesn't mean that you couldn't use it as one anyway.

    I doubt that there is really anything magic going on under the covers that would act specially upon objects formerly blessed as Regexp.

    my @a=qw(random brilliant braindead); print $a[rand(@a)];

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://161902]
Approved by broquaint
Front-paged by giulienk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (5)
As of 2024-03-28 20:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found