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

Hi again,

What's wrong with the code below? I get repeated values for each school matched.

my $file = 'schools.txt'; open (FH, "$file") or die $!; my @schools; while (my $line = <FH>) { $line =~ m/\s([\w ]+? PRIMARY SCHOOL)/; push (@schools, $1) if $1; } print "@schools\n"; # Sample data from schools.txt SCH CODE, ZONE SCHOOL NAME & ADDRESS PRINCIPAL & VICE-PRINCIPAL TELEPHONE, FAX NUMBERS & EMAIL ADDRESS ---------------------------------------------------------------------- +---------- 1744 North ADMIRALTY PRIMARY SCHOOL ???? 11 WOODLANDS CIRCLE SINGAPORE 739807 P : MDM LIM SOH LIAN ??? VP: MR TAN MENG HUI ??? Tel: 63620598 Fax: 63627512 ADMIRALTY_PS@MOE.EDU.SG ---------------------------------------------------------------------- +---------- 1738 North AHMAD IBRAHIM PRIMARY SCHOOL ?????? 10 YISHUN STREET 11 SINGAPORE 768643 P : MISS FOONG YIN WEI ??? Tel: 67592906 Fax: 67592927 AIPS@MOE.EDU.SG

Replies are listed 'Best First'.
•Re: Why repeated matches...
by merlyn (Sage) on Dec 13, 2003 at 17:48 UTC
Re: Why repeated matches...
by Anonymous Monk on Dec 13, 2003 at 17:52 UTC

    Once your regex succeeds, $1 holds its value until the next time the regex *succeeds*. You want to conditionalize your use of $1 to only when the regex succeeds, not to when $1 is true:

    while (my $line = <FH>) { next unless $line =~ m/\s([\w ]+? PRIMARY SCHOOL)/; push (@schools, $1); }
Re: Why repeated matches...
by delirium (Chaplain) on Dec 14, 2003 at 00:34 UTC
    Less reformatting of code:

    while (my $line = <FH>) { $line =~ m/\s([\w ]+? PRIMARY SCHOOL)/ || next; push @schools, $1; }

    Or you could get sneaky:

    @schools = grep {/\s([\w ]+? PRIMARY SCHOOL)/; $_ = $1} <FH>;
      Sneakier still:
      @schools = map /\s([\w ]+? PRIMARY SCHOOL)/, <FH>;
      map creates a list of matches, here consisting only of $1, when it matches, and an empty list when it fails to match.
Re: Why repeated matches...
by carric (Beadle) on Dec 14, 2003 at 00:25 UTC
    Here is another possile way to write it:
    #!/usr/bin/perl -w use strict; my $file=shift; # get the name of file you # you are passing to script open (FH,$file) || die "Can't open - $!\n"; my @schools; while(<FH>) { if(//\s([\w ]+? PRIMARY SCHOOL)/) { push(@schools, $1); } } close FH;