Scotty
Scotty

Reputation: 15

Perl variable doesn't stay set, even when set with "our"

I have a file that I wish to search for strings, matching with items stored in an array. I open the file, loop through it and when I find what I'm looking for, I change a variable flag so additional work can be done. I am having an issue where the variable I set is not sticking. I placed the variable within the foreach loop, made it an our variable, to no avail.

Questionable code:

my $zed = 0;
foreach my $SUB (@sub) {
    print "We are currently looking for $SUB<br><br>";

    open (my $input, "<", "C:\\Users\\scottbro\\Desktop\\PMS.txt")
        or die "Cannot open PMS.txt: $!";

    our $flag = 0;
    ##SET Zed to keep track of where we are
    print "Zed is $zed<br>Flag is $flag<br>";
    $zed++;

    while (<$input>) {

        print "inside the while loop, flag is now $flag<br>";
        ##  IF you find what you are looking for, set flag to 1
        if (/$SUB/) {
            $flag = 1;
            print "Found sub property, flag is now $flag<br>";
            ## IF flag is 1, and line has email address, show it!
        } elsif ($flag = 1 && /<email>(.+)/) {
            print "Flag is $flag, email is $1<br>";
        }

    }
    close($input);
}

Output, where it can be seen the flag variable loses value:

We are currently looking for Property 1
Zed is 0
Flag is 0
inside the while loop, flag is now 0
inside the while loop, flag is now 
Flag is 1, email is email1
inside the while loop, flag is now 1
Flag is 1, email is email2
inside the while loop, flag is now 1
inside the while loop, flag is now 
inside the while loop, flag is now 
inside the while loop, flag is now 
Found sub property, flag is now 1
inside the while loop, flag is now 1
Flag is 1, email is email3
inside the while loop, flag is now 1
Flag is 1, email is email4
inside the while loop, flag is now 1
inside the while loop, flag is now 
inside the while loop, flag is now 
Flag is 1, email is email 5

Upvotes: 1

Views: 144

Answers (2)

Borodin
Borodin

Reputation: 126722

You are assigning to $flag in your test

elsif  (  $flag=1 && /<email>(.+)/ ) {  ... }

is setting $flag to 1 && /<email>(.+)/ which is false if the regex pattern doesn't match

It should probably be

if  (  $flag and /<email>(.+)/ ) { ... }



I suggest you forget about $flag and instead use the fact that the input file will be at eof if $sub hasn't been found, so the program won't be able to read anything further anyway

It's also nicer to rewind the file rather than reopen it. It's almost certain that the data should be parsed into a hash and accessed directly, but I can't tell for sure with the little information you give

my @sub;

open my $fh, '<', 'C:\Users\scottbro\Desktop\PMS.txt' or die "Cannot open PMS.txt: $!";

for my $sub ( @sub ) {

    seek $fh, 0, 0;

    while ( <$fh> ) {
        last if /$sub/;
    }

    while ( <$fh> ) {
        next unless /<email>(.+)/;
        print qq{Email for "$sub" is "$1"};
        last;
    }
}

Upvotes: 4

ikegami
ikegami

Reputation: 385897

You are assigning to $flag in your test rather than checking its value.

elsif ($flag = 1 && /<email>(.+)/)

should be

elsif ($flag == 1 && /<email>(.+)/)

Or even better,

elsif ($flag && /<email>(.+)/)

That said, repeatedly reading the same file is quite inefficient. Here's a version that doesn't.

my $pat = join '|', map quotemeta, @subs;

my $qfn = 'C:\\Users\\scottbro\\Desktop\\PMS.txt';
open(my $fh, '<', $qfn)
   or die(qq{"Can't open "$qfn": $!\n"});

while (<$fh>) {
   my ($sub) = /($pat)/
      or next;

   defined( $_ = <$fh> )
      or last;

   my ($email) = /<email>(.+)/
      or redo;

   print(qq{Email for "$sub" is "$email"\n});
}

Upvotes: -2

Related Questions