http://qs1969.pair.com?node_id=383991

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

I have tried to match a pattern stored in a variable like so 08/14/04.
my $dm=08/14/04; open F, file while (<F>) { if ( $_ =~ /$dm/ ) { blah blah blah } if ( $_ =~ m/^\$dm/ ) if ( $_ =~ m/[$dm]/ )
I cannot get it to pull on certain dates from a file. My file looks like 08/14/04 timestampe exxxxx

20040819 Edit by broquaint: Changed title from 'reg exp'

Replies are listed 'Best First'.
Re: regex match with interpolated pattern
by hv (Prior) on Aug 18, 2004 at 15:23 UTC
    my $dm=08/14/04;

    Since the value isn't in quotes, this is actually a calculation involving two divisions. Try instead:

    my $dm = '08/14/04';

    Hugo

Re: regex match with interpolated pattern
by davorg (Chancellor) on Aug 18, 2004 at 15:24 UTC

    That code won't even compile. Please don't retype code. Paste your _real_ code into your post so that we have a chance of seeing what is really going wrong.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: regex match with interpolated pattern
by dsb (Chaplain) on Aug 18, 2004 at 15:24 UTC
    You're date variable is using / as the delimiter. As a result you aren't matching the pattern you think you are. You could just use a different delimiter for your pattern.
    if ($_ = m%$dm%) { #stuff }
    Or you could call quotemeta() on your variable.
    my $dm = quotemeta($date);
    quotemeta() will escape all non-word characters.

    UPDATE: After reading hv's reply, I agree with him. SOmething didn't seem right to me as I was replying...he caught it though :)


    dsb
    This @ISA my cool %SIG
      You're date variable is using / as the delimiter. As a result you aren't matching the pattern you think you are. You could just use a different delimiter for your pattern.
      if ($_ = m%$dm%) { #stuff }
      If you are interpolating a string it does not matter if it has characters that are the same as the delimiter. The boundaries of the regex are determined before the interpolation is done. Try this:
      perl -e '$string = "/"; print "08/14/04"=~/$string/ ? "matched\n" : "no match\n"'
      ok men, I tried all 3 suggestions and none worked so here is my code. Again $dm and $dmm are dereived from the subroutines are are in format xx/xx/xx
      sub date_manip { my ($month, $day, $year) = (localtime)[4,3,5]; sprintf ("%02d/%02d/%02d\n", $month+1,$day,($year % 10 +0)); } my $dm = '&date_manip'; sub date_manip1 { my $days = (shift); my ($d, $m, $y) = (localtime($time - $days * 86400)) [ +3..5]; sprintf ("%02d/%02d/%02d", $m+1,$d,($y % 100)); } my $dmm = '&date_manip1(1)'; #print ("$dm $dmm"); ############################################################ ## Gather data for scratch tapes; open file, create list, then print i +t. ## ############################################################ open (FOO, ">$scratches") || die "could not open file:$!"; #($^I, @ARGV) = ('.bak', $scratches); open (D, "$logf") || die "could not open file:$!"; while (<D>) { ## look for 9840S and ebexpire ## declare OFS = tab ## tell split to split on IRS 0,1&5. # if (($_ =~ /9840S/) && ($_ =~ /ebexpire, ebexpire/ ) +) { if (($_ =~ /9840S/) && ($_ =~ /ebexpire, ebexpire/ ) & +& ( $_ =~ m/$dm/) && ($_ =~ m/$dmm/)) { local $, = "\t"; print FOO +(split)[0,1,5], $/ ; } } close (FOO); close (D);
        This code works (that is, the print executes) for me, and should work for you:
        $dm='08/14/04'; $_='There is an 08/14/04 in here'; if ($_ =~ m/$dm/) { print "Matched on <$_>\n"; }
        The code you've included so far hasn't been the kind of test code we'd most like to see, which is an actual program that we can run that demonstrates the problem.

        In this last excerpt, you're quoting your subroutine calls, which results in the subroutines not being called. Also, you're putting a newline in your date_manip, which may not be what you want. Here's a test-code modification that may help you out:

        #!perl sub date_manip { my ($month, $day, $year) = (localtime)[4,3,5]; sprintf ("%02d/%02d/%02d\n", $month+1,$day,($year % 100)); } my $dm = &date_manip; sub date_manip1 { my $days = (shift); my ($d, $m, $y) = (localtime($time - $days * 86400)) [3..5]; sprintf ("%02d/%02d/%02d", $m+1,$d,($y % 100)); } my $dmm = &date_manip1(1); print ("{$dm} {$dmm}\n"); ############################################################ ## Gather data for scratch tapes; open file, create list, then print i +t. ## ############################################################ while (<DATA>) { print "-- Checking <$_>\n"; print "Found 9840\n" if /9840S/; print "Found ebexpire\n" if /ebexpire, ebexpire/; print "Found $dm\n" if /$dm/; print "Found $dmm\n" if /$dmm/; } __DATA__ 9840S ebexpire, ebexpire 12/30/69 08/18/04 9840S ebexpire, ebeXpire 12/30/69 08/18/04 9840S ebexpire, ebexpire XX/30/69 08/18/04

        Caution: Contents may have been coded under pressure.

        Uncomment your print ("$dm $dmm");. You'll see that you actually have the literal strings '&date_manip' and '&date_manip1(1)' in them. That's why they're not matching something that looks like a date.

        Just use:

        $dm = date_manip(); $dmm = date_manip1(1);

        And you'll be a lot closer.

        You also may wish to check out Date::Calc and Date::Manip and choose one for your date routines.