Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

passing qr//'d regexp via Perl/Tk Entry widget

by young_stu (Beadle)
on Jun 23, 2005 at 21:17 UTC ( #469522=perlquestion: print w/replies, xml ) Need Help??

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

Hello All:

I'm working on a Perl/Tk gui that I hope will allow a user to type a regexp into an entry widget for matching against some text. I'd like to to be true that the user, if he or she pleases, may supply a qr//'d regexp. So far, what seems to me to be the obvious way to do it has failed.

The following code demonstrates the failure...
use warnings; use strict; use Tk; my $string = "foobarbaz"; my $mw = MainWindow->new; my $regexp_entry = $mw -> Entry() -> pack; my $go_button = $mw -> Button( -takefocus => 1, -text => "Match using what you typed!", -command => sub{ my $exp = $regexp_entry -> get(); print STDOUT "I'm looking for a match for $exp...\n"; $string =~ m/$exp/ ? print STDOUT "match!\n" : print STDOUT "N +o match!\n"; } )-> pack; my $used_stored_exp = $mw -> Button( -text => "Match with Stored Regexp!", -command => sub{ my $exp = qr/foo/; print STDOUT "I'm looking for a match for $exp...\n"; $string =~ m/$exp/ ? print STDOUT "match!\n" : print STDOUT "N +o match!\n"; } )-> pack; $regexp_entry -> focus; MainLoop;
To see the failure, run the script and do the following:
(1)press the "Match using stored Regexp" button, and watch your STDOUT line.
(2)type
qr/foo/
into the entry widget, press the "Match using what you typed!" button, and watch STDOUT.

Surprisingly (perhaps only to a neophyte like me) it "works" if in step (2) above, you instead type
(?-xism:foo)
into the entry widget.

What's going on here? My first guess is that there's something happening with the entry widget's "get" method

Thanks!

Replies are listed 'Best First'.
Re: passing qr//'d regexp via Perl/Tk Entry widget
by crashtest (Curate) on Jun 23, 2005 at 22:29 UTC
    I ran your code, and it behaves as I would expect. If I type in "barbaz$" or "oob" and hit the $go_button, I get a match, and if I type "foot" or "xyz", I don't get a match. Isn't this exactly what you want?

    I am guessing you think the input text has to be wrapped in a qr// for it to work, but that's not the case. You only need to feed a regular-expression string to m//, not a regular-expression object (which you construct with qr//), In fact, since qr// is really just a chunk of perl code, you would need to eval it to get it to work. Replacing the last line of your command sub for $go_button with the following would force users to enter their regular expression using qr//:
    $string =~ eval $exp ? print STDOUT "match!\n" : print STDOUT "No matc +h!\n";
    It is only by chance that (?-xism:foo) matches "foobarbaz" - it has nothing to do with the fact that this is the string representation of the regular expression qr/foo/. The "(?-xism:" signals the start of a non-capturing grouping with the x, i, s and m modifiers turned off. This little construct is buried within perlre. I can't say I ever realized that the stringification of a regular expression is itself another related, similar regular expression.

    Update: Boy do I feel like a fool! Whenever Perl printed (?-xism:the regex), I always read it as "Regular expression-ism: 'the regex'". As in "The United States' policy was one of protectionism". I never realized Perl was being helpful and showing me the modifiers it was (or wasn't) using.

      I guess I need to clarify why the behavior of this script puzzles me, and say a bit more about what I ulimately want to do:

      This script puzzles me because if I wrote:
      my $string = "foobarbaz"; my $exp = qr/foo/; print STDOUT "matching $exp...\n"; print STDOUT "match!\n" if $string =~ m/$exp/;
      I would get what I expect...i.e. I would see:
      matching (?-xism:foo)... match!
      But when the regexp object qr/foo/ is instead assigned to the variable $exp via the get method, it (seems) to cease to be a regexp object. In fact, it seems to become the string literal 'qr/foo/'. So what is the get method doing to my regexp object and how can I make it stop?

      The other thing is that I want the user to have the _choice_ to pass a regexp in a qr//, in double quoted string, or in single quoted string, as he or she sees fit given the context. There's good reason for this. For instance, many users may not know that they can pass modifiers (say /s) via the "(?:s foo)" "span" operator, but may know that they can get the same effect by writing qr/foo/s. In otherwords, I want it to be true that my Perl/Tk app allows "more than one way to do it." Otherwise "requiring" users to enter, say, everthing as a qr// object would be ok.

      Thanks!
        But when the regexp object qr/foo/ is instead assigned to the variable $exp via the get method, it (seems) to cease to be a regexp object. In fact, it seems to become the string literal 'qr/foo/'. So what is the get method doing to my regexp object and how can I make it stop?
        You're hitting the nail on the head, but not seeing it, I think. When you type "qr/foo/" into your entry widget, it is just a string. It never "ceases" to be a regular expression object - it never was one. You might have typed anything into your text box, a limmerick or a dirty word or anything. Just because the text is "qr/foo/", and happens to be a string that stands for a regular expression object in the Perl language is immaterial. The program won't look at the text and say, aha, this is a perl construct. It's just text.

        This is completely different from writing my $exp = qr/foo/; in your perl script. This is part of your program (and not your program input), and perl knows how to parse this. If, instead of my $exp = qr/foo/; you wrote my $exp = "qr/foo/";, you would get the same behavior as when the regex is passed via your text entry widget.

        If you want Perl to parse and interpret the entered text as a chunk of Perl code, you need to use the string version of eval. That tells perl that the text passed in is more than text, and to evaluate it as a Perl expression. I hope this makes sense.

        As for allowing a user several ways to pass a regular expression, you should read the text entered and adjust your processing accordingly, like injunjoel suggests. Something like this (completely untested):
        my $regexp = undef; my $entered_text = $regexp_entry -> get(); if ($entered_text =~ m!^qr/!){ # User has passed a "qr//" type regex: $regexp = eval $entered_text; } else{ # User has passed a straight regular expression $regexp = m/$entered_text/; }
        Note that there is no need in the "else" branch for the user to have enclosed their code in single- or double-quotes. You are reading text from the widget, then using that text to construct a regular expression at run time.

Re: passing qr//'d regexp via Perl/Tk Entry widget
by injunjoel (Priest) on Jun 23, 2005 at 22:18 UTC
    Greetings,
    I feel this has more to do with the binding operator  =~ than it does with your entry widgets get method. Here is the perlop snippet that makes me think so. clipped for clarity
    ...``=~'' binds a scalar expression to a pattern match. ... (If the right argument is an expression rather than a search pattern, substitution, or transliteration, it is interpreted as a search pattern at run time.

    So if you simply type in "foo" you get a match since the  =~ seems to be treating it as /foo/ by default.
    One workaround might be to strip off the "qr/" and trailing "/" prior to the match.
    Here is an example of the behavior
    #!/usr/bin/perl -w use strict; my $string = "foobarbaz"; my $exp = "foo"; if($string =~ $exp){ print "without /'s works fine"; }elsif($string =~ /$exp/){ print "with /'s is needed"; }else{ print "WTF!??"; }

    This outputs
    without /'s works fine
    -InjunJoel
    "I do not feel obliged to believe that the same God who endowed us with sense, reason and intellect has intended us to forego their use." -Galileo

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://469522]
Approved by moot
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (1)
As of 2019-08-21 04:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?