Thanks for the great explanation. I've been working with the code above
since I need more hash practice, trying to keep on track with the
original poster's question. The code below works fine except I can't
figure out how to put one "\n" between the two records like -
Name: Bob City: Austin State: Texas
Name: Jose City: Denver State: Colorado
If I place "print "\n";" after the print line I get double spaces between all lines. If I place it outside the last "for" loop I get double spaces between the two records. What I have below just prints them in one block. Hope that all made some sense:)
I'm with you. See below.
Thanks for any help, Kent
#!/usr/bin/perl use warnings; use strict;
You forgot a very important line from my example right here:
local $/ = ''; # enter "paragraph" mode
Your code was reading line by line, then working on just that line. You never had more than one entry in the hash at a time.
My example reads until it sees one or more blanks lines (paragraph mode), then works with an entire contact at once.
That almost fixes you up, but we have to do a little more.
while (<DATA>) { my @lines = (split /\n/, $_); my %contact; for my $line (@lines) { if ($line =~ /^(\w+):\s*(.+)$/) { $contact{$1} = $2;
The for loop below is in the wrong spot. Here we're processing each line of the hash, so the loop would get run once for each and every line, giving us erroneous output. We need to move it down a bit...
for (keys %contact) { if (/^Name/ or /^City/ or /^State/) {
Minor complaint about the line above. Don't use a Regex to test equality. Save the big guns for when you actually need pattern matching. It should read:
if ($_ eq 'Name' || $_ eq 'City' || $_ eq 'State') {
print "$_: $contact{$_}\n"; } } } }
Move that for loop I mentioned above to here and add a:
print "\n";
after the loop. That "fixes" your program. Let's look into it a little more though...
}
Putting everything I've said so far together, we get the code:
#!/usr/bin/perl
use warnings; use strict;
local $/ = '';
while (<DATA>) { my @lines = (split /\n/, $_); my %contact; for my $line (@lines) { if ($line =~ /^(\w+):\s*(.+)$/) { $contact{$1} = $2; } } for (keys %contact) { if ($_ eq 'Name' || $_ eq 'City' || $_ eq 'State') { print "$_: $contact{$_}\n"; } } print "\n"; }
__DATA__ Name: Bob City: Austin State: Texas Address: 123 Whatever Age: 46
Name: Jose City: Denver State: Colorado Address: 118 Mystreet Age: 28
Go ahead and paste that into a file and run it a few times for some interesting results.
Do you see it? The order of the output changes with subsequent runs if you're running a fairly recent version of perl.
I don't think it was ever said if order is significant in this problem, but the behavior is annoying so let's fix it too. The "problem" is in the output loop:
for (keys %contact) { if ($_ eq 'Name' || $_ eq 'City' || $_ eq 'State') { print "$_: $contact{$_}\n"; } }
That loop fetches all the keys of the hash and then prints the Name, City and State as it finds them. Trouble is, perl isn't guaranteed to return those keys in a set order and indeed it doesn't. The loop is also wasteful as it has to go through keys we don't care about. Let's change it to ask for what we want instead:
for (qw(Name City State)) { print "$_: $contact{$_}\n"; }
That does it. The program now returns what we expect every time it's run.
Hope that clears things up for you.
James
-- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] <http://learn.perl.org/> <http://learn.perl.org/first-response>