Reputation: 43
I am pretty new to Perl. I have the following code fragment that works just fine, but I don't fully understand it:
for ($i = 1; $i <= $pop->Count(); $i++) {
foreach ( $pop->Head( $i ) ) {
/^(From|Subject):\s+/i and print $_, "\n";
}
}
$pop->Head is a string or an array of strings returned by the function Mail::POP3Client, and it is the headers of a bunch of emails. Line 3 is some kind of regular expression that extracts the FROM and the SUBJECT from the header.
My question is how does the print function only print the From and the Subject without all the other stuff in the header? What does "and" mean - this surely can't be a boolean and can it? Most important, I want to put the From string into its own variable (my $fromline). How do I do this?
I am hoping that this will be easy for some Perl professional, it has got me baffled!
Thanks in advance.
Upvotes: 2
Views: 86
Reputation: 1583
ARGHHH... The question was edited while I was typing the answer. OK, throwing out the part of my answer that's no longer relevant, and focusing on the specific questions:
The outer loop iterates over all the messages in the mailbox.
The inner loop doesn't specify a loop variable, so the special variable $_
is used.
In each iteration through the inner loop, $_
is one header line from message number $i
.
/^(From|Subject):\s+/i and print $_, "\n";
The first part of this line, up to the and
is a pattern. We didn't specify what to do with the pattern, so it's implicitly matched against $_
. (That's one of the things that makes $_
special.) This gives us a yes/no test: does the pattern match the header line or not?
The pattern tests whether that item begins with (<
) either of the words "From" or "Subject", followed immediately by a colon and one or more whitespace characters. (This not the correct pattern to match an RFC 822 header. Whitespace is optional on both sides of the colon. The pattern should more properly be /^(From|Subject)\s*:\s*/i
. But that's a separate issue.) the i
at the end of the pattern says to ignore case, so from
or SUBJECT
would be OK.
The and
says to continue evaluating (i.e., executing) the expression if there is a match. If there's no match, whatever follows and
is ignored.
The rest of the expression prints the header line ($_
) and a newline ("\n"
).
In perl, and
and or
are boolean operators. They're synonyms for &&
and ||
, except that they have much lower precedence, making it easier to write short-ciruit expressions without clutter from lots of parentheses.
The smallest change that captures the From line into a separate variable would be to add the following line to the inner loop:
/^From\s*:\s*(.*)$/i and $fromline = $1;
You should probably also put
$fromline = undef
before the loop so you can test, after the loop, whether there was a From: line.
There are other ways to do it. In fact, that's one of the mantras of perl: "There's more than one way to do it." I've stripped out the "From: " from the beginning of the line before storing the balance in $fromline
, but I don't know your needs.
Upvotes: 4
Reputation: 5290
It's a logical and
with short-circuiting. If the left side evaluates to true -- say, if that regular expression matches -- it'll evaluate the right side, the print
.
If the expression on the left is false, it doesn't need to evaluate the right hand side, because the net result would still be false, so it skips it.
See also: perldoc perlop
Upvotes: 0