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

I do not understand regular expressions. That being said I have tried, but the "ah ha" moment when the syntax finally makes sense I still wait upon as I read tutorial after tutorial.
I've been working on a program to collect user data so that I can be lazy at work. I have to answer about 10 "Do you know where I forwared my mail to?" type questions and about 5 "Can you setup my account with a vacation message?" type questions per shift. It gets old fast; so I've got a script that will jump from server to server (using Net::SSH) looking at files and changing them depending on what I tell it to do. It works fine, but I have designs on making users use a non-root version from the web (Net::SSH::Perl so I can get their passwords and login as them) of it so they don't even have to ask me.
That being said I need to clean up the output a bit. So I was wondering about a regular expression that could match the following output.
cat: cannot open $HOME/$library::common{username}/filename Can't open $HOME/$library::common{username}/filename
$HOME and $library::common{username} are scalars (well kinda) that hold data. I do not need to match their names, but instead what they contain. I would much rather handle both of those cases in one regular expression then in two seperate if statements. The best i have turned up so far is
if($vacation_str =~ /^.*$HOME\/$library::common{username}\/.vacation.m +sg/i)
and it does not work. Tips anyone?

jcpunk
all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)

Replies are listed 'Best First'.
Re: a really dumb regular expression question
by Roger (Parson) on Jan 19, 2004 at 03:24 UTC
    I tried it and it seems to work.
    if ($vacation_str =~ m!$HOME/$library::common{username}/!i) { ...

    I have written a little demo to show how to perform regular expression match -
    use strict; use warnings; my $HOME = '/usr/home'; my %common; $common{username} = 'roger'; my @str = ( 'cat: cannot open $HOME/$common{username}/filename', "Can't open $HOME/$common{username}/filename !", "This is some other string" ); foreach my $vacation_str (@str) { print "$vacation_str\n"; # case 1 - match exact string if ($vacation_str =~ m!\$HOME/\$common{username}/filename!i) # case 2 - match interpolated string #if ($vacation_str =~ m!$HOME/$common{username}/filename!i) { print "match\n"; } else { print "not match\n"; } }

    Case 1 output -
    cat: cannot open $HOME/$common{username}/filename match Can't open /usr/home/roger/filename ! not match This is some other string not match

    Case 2 output -
    cat: cannot open $HOME/$common{username}/filename not match Can't open /usr/home/roger/filename ! match This is some other string not match

      eureka.
      i thank thee

      jcpunk
      all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)
Re: a really dumb regular expression question
by Wassercrats (Initiate) on Jan 19, 2004 at 04:52 UTC
    Also, remember that the dots surrounding "vacation" are metacharacters unless you escape them with backslashes.
      Right, i will make sure to keep an eye on that.
      thanks for the tip

      jcpunk
      all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)
Re: a really dumb regular expression question
by Aragorn (Curate) on Jan 19, 2004 at 08:50 UTC
    I do not understand regular expressions. That being said I have tried, but the "ah ha" moment when the syntax finally makes sense I still wait upon as I read tutorial after tutorial.
    I recommend that you get hold of a copy of Mastering Regular Expressions, 2nd Edition. If it doesn't ”click“ after studying that, it probably never will.

    Arjen

      Thanks, i have just purchased the text. Good old the Internet :) in three or four days you can own anything.

      jcpunk
      all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)
Re: a really dumb regular expression question
by theAcolyte (Pilgrim) on Jan 19, 2004 at 09:27 UTC
    It takes a while for it to really sink in, sometimes. I've hit the ah-ha moment, but I still make mistakes, do things inefficently .... etc. but I'm getting the hang of it. That being said ... your RE:
    if($vacation_str =~ /^.*$HOME\/$library::common{username}\/.vacation.m +sg/i)
    has a fairly major problem you should be aware of. You start out by saying:
    ^  # match the begining of a line
    .  # match any character
    *  # match 0 or more occourances of the preceeding character.
    
    So, what you've said is ... match any line, the entire line, from begining to end. Oopse?

    By default, operators like .* make things 'greedy' -- they match as much as possible. You can make it non-greed -- matchign as little as possible -- like this:

    $myVar =~m/^.*?Help/;
    now you're matching any chars, starting at the begining of the line, up until the regEx engine hits a 'Help'.

    Hope that helps.

    Oh, and another thing.. you may want to read perlre in the perl docs that come with the standard distribution. Reading through that, slowly, and several times whilst trying the examples in a script really helped me get my poor excuse for a brain wrapped around re's.

    - Erik

      Thanks for that 'perl' (i am so not funny) of wisdom. I will again make a trek into perlre perhaps I will be able to gleen a bit more from it this time.

      jcpunk
      all code is tested, and doesn't work so there :p (varient on common PM sig for my own ammusment)
Re: a really dumb regular expression question
by Wassercrats (Initiate) on Jan 19, 2004 at 03:18 UTC
    I think braces are metacharacters. Maybe you should assign $library::common{username} to a simple variable, like $LIB. But first, try putting \Q before each variable and \E after each variable.
      Braces are not interpreted as metacharacters inside of a regular expression if they are intended to be part of a variable interpolation instead.

      use warnings; $main::look{mom} = "works"; my $var = "It works!"; if ( $var =~ /$main::look{mom}/ ) { print "Guess what! It matched!\n"; }

      Variable interpolation occurs before the regexp engine revs up and starts its work. See perlop under the "Gory details of parsing quoted constructs" section. The variable interpolation stage gets performed a couple passes before the regexp engine kicks in.

      However, it may still be necessary to use \Q and \E, if the content of your interpolated variable could, itself, be misinterpreted as metacharacters.

      Here's contrived example of a ? and a . being seen as metacharacters when they were probably intended to be seen as literal text:

      use strict; use warnings; my $test_interpolation = "Old McDonald had a farm?."; if ( "Old McDonald had a fart " =~ m/$test_interpolation/ ) { print "Ewwwww!\n"; } __OUTPUT__ Ewwwww!

      Wrapping a \Q and \E around the variable interpolation inside the regexp would cure this problem, as would using the quotemeta function.


      Dave