Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Using pattern match

by tceng (Novice)
on Aug 10, 2007 at 11:01 UTC ( [id://631755]=perlquestion: print w/replies, xml ) Need Help??

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

Hi there, please, I'd like to know if there's an easy solution to do what I am expecting from a script like this one:
#!/usr/bin/perl -w my %triggers = ( 'You are (\\w+).' => 'Your status is: $1', ); my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { #print "Memory contents of \$1: $1\n"; print $triggers{$trigger}; } } print "\n";
I'd like it to print out:
Your status is: fired

Instead of:
Your status is: $1

I know we can use a regular expression in a variable ($trigger in the example) for expression matching, but I do not know how to use a variable to retrieve the memory holders ($1, $2, etc.) after a match occurred with (\w+) or (\d+) and such.
Can anyone please help with that?
Cheers,

tceng

Replies are listed 'Best First'.
Re: Using pattern match
by akho (Hermit) on Aug 10, 2007 at 11:09 UTC
    $1 doesn't have a value when you define %triggers. You can postpone the evaluation of your string using a sub:
    #!/usr/bin/perl -w use strict; my %triggers = ( 'You are (\\w+).' => sub { "Your status is: $1" }, ); my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { #print "Memory contents of \$1: $1\n"; print &{$triggers{$trigger}}; } } print "\n";
      Thank you very much, akho. It works perfectly now.

      Cheers,

      tceng
Re: Using pattern match
by moritz (Cardinal) on Aug 10, 2007 at 11:43 UTC
    Instead ofthe solution with the sub (which is better than mine ;) you can use eval:

    #!/usr/bin/perl -w my %triggers = ( 'You are (\\w+).' => '"Your status is: $1"', ); my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { #print "Memory contents of \$1: $1\n"; print eval $triggers{$trigger}; } } print "\n";

    The evil string eval strips the inner double quotes of the string and interpolates $1.

      Thank you all for your help.

      Now I am trying to add another intricacy, that is user input:
      #!/usr/bin/perl -w # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; my $trigger_action = sub { $trigger_action_str }; $triggers{$trigger_name} = $trigger_action; #print "$trigger_name -> $trigger_action_str\n"; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { #print "Memory contents of \$1: $1\n"; print &{$triggers{$trigger}}; } } print "\n";
      If I try to run this:
      perl triggers2.pl "You are (\w+)." "You are: $1"
      it doesn't work.
      Any advice, please? Would the eval solution work with this?
      Cheers,

      tceng
        The shell is eating $1. Escape the dollar: \$1 or use single quotes on the command line.

        Yes, you will definitely need string eval here.

        Something like this:

        #!/usr/bin/perl -w use strict; # builtin triggers my %triggers; # add triggers from params my $trigger_name = shift @ARGV; my $trigger_action_str = shift @ARGV; $triggers{$trigger_name} = $trigger_action_str; my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { print eval '"' . $triggers{$trigger} . '\n"'; } }

        But this is not a design anyone will recommend.

        Besides, this will not run in taint mode.

        the eval() solution would work in the above case, but be advised that this approach is even eviler than (string) eval() used on its own. this is because code can be evaluated at run time both in eval() and in the extended regex pattern (?{{ code... }}).

        see the subject of taint checking and perlsec for more horrific details.

Re: Using pattern match
by Moron (Curate) on Aug 10, 2007 at 11:34 UTC
    There is also the fact that single quotes produce literally what is there rather than translating $variables. The example with sub has used double quotes whereas the OP didn't. So instead of using sub, it so happens you could also achieve the delay by keeping the single quotes and putting an eval around what is being printed and of course it makes me wonder if the OP code originated in or was copied from that kind of example somewhere.
    __________________________________________________________________________________

    ^M Free your mind!

      Darn. It seems like every time there's an issue I can actually speak with some authority (quotes and variable interpolation), somebody has beaten me to the punch and has a better answer.

      Guess I'll just keep learnin' until I can answer the less easy stuff :).

Re: Using pattern match
by Anonymous Monk on Aug 10, 2007 at 18:04 UTC

    May be I am missing something obvious, but wouldn't a simple printf work ? (assuming there is only one variable needed).

    Something like that :

    #!/usr/bin/perl -w my %triggers = ( 'You are (\\w+).' => 'Your status is: %s', ); my $buff = "You are fired!"; foreach my $trigger ( keys ( %triggers ) ) { if ( $buff =~ /$trigger/ ) { print sprintf( $triggers{$trigger}, $1); } } print "\n";
        Thank you for your contribute!
        Unfortunately the idea was to be able to process regular expressions with more than one matching patter and be able to print out something that involves those matching patterns.
        I think it would help if Perl generates a list whose elements are all the matching patterns in a s/// operation. Ie that list contains $1, $2, $3, and so on, and a foreach can be done on it, so that one can pick up all the defined variables in one go and then substitute them with the method I showed before (s/\$1/$1/g). Is there one such list, please?

        Cheers,

        tceng

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-04-19 22:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found