CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Parsing text file using perl similarly named fields are not parsed correctly

 



rlovell6
Novice

Feb 22, 2016, 5:13 AM

Post #1 of 9 (2289 views)
Parsing text file using perl similarly named fields are not parsed correctly Can't Post

I am very new to Perl and am trying to parse a text file for certain fields in each record. A record would look as follows:

Name = John Doe
Addr = 1 main st.
zipcode = 12345
phonenumber = 123-456-7890
phonenumber2 = 234-567-8901
rentorown = rent

I want only the name, zipcode, phonenumber, and phonenumber2 if it exists. originally I wasn't interested in phone numbers and wrote a script that worked, however now I need the phone numbers and it is causing me problems because not every record has a phonenumber2 field, if they don't have a second phone then the attribute isn't even listed. My output now has the phone numbers wrong for every record after the first one containing two numbers. below is my code.


Code
 
open(my $in, '<', 'Customer.dat')
or die "Cannot open input file: $!";

my @Name;
my @Zip;
my @Phone;
my @Phone2;

my $i = 0;

for my $attribute(<$in>) {
chomp $attribute;

if ($attribute =~ /Name/)

{
push(@Name, $attribute);

}
if ($attribute =~ /zipcode/)
{

push(@Zip, $attribute);

}
if ($attribute =~ /phonenumber/)
{

push(@Phone, $attribute);

}
if ($attribute =~ /phonenumber2/)
{

push(@Phone2, $attribute);
$1++;
}

open(my $out, '>>', 'CustomerInfo.csv') or die "oops $!";

my $n = 0;

do {
print $out $Name[$n];
print $out ", ";
print $out $Zip[$n];
print $out ", ";
print $out $Phone[$n];
print $out ", ";
print $out $Phone2[$n]\n";
$n++;
} while($n < $i);


close($in);


Thank you for any help!


FishMonger
Veteran / Moderator

Feb 22, 2016, 8:53 AM

Post #2 of 9 (2278 views)
Re: [rlovell6] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

Is each record separated by a blank line or something else or are they strung together without any type of separator?


rlovell6
Novice

Feb 22, 2016, 9:15 AM

Post #3 of 9 (2274 views)
Re: [FishMonger] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

There is a blank line between records and Each Record would start with the same line of text such as 'Customer Record' which would let you know you are starting a new record.


(This post was edited by rlovell6 on Feb 22, 2016, 9:16 AM)


FishMonger
Veteran / Moderator

Feb 22, 2016, 4:40 PM

Post #4 of 9 (2250 views)
Re: [rlovell6] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

Instead of reading the file line-by-line, read it in paragraph mode so that each read of the filehandle bring in the whole record of 5 or 6 lines.

Then use the split function when looping over the record elements and build up a HoH (Hash of Hashes).


Code
#!/usr/bin/perl 

use warnings;
use strict;
use Data::Dumper;

$/ = "";

my %cust_record;
while (my $record = <DATA>) {
my ($customer, @cust_info) = split /\n/, $record;
my $name = (split /\s*=\s*/, $customer)[1];

foreach my $info (@cust_info) {
my ($key, $value) = split /\s*=\s*/, $info;
$cust_record{$name}{$key} = $value;
}
}
print Dumper \%cust_record;


__DATA__
Name = John Doe
Addr = 1 main st.
zipcode = 12345
phonenumber = 123-456-7890
phonenumber2 = 234-567-8901
rentorown = rent

Name = Jane Doe
Addr = 10 Downing st.
zipcode = 54321
phonenumber = 987-65-4321
rentorown = own



Code
c:\test>Perl-1.pl 
$VAR1 = {
'John Doe' => {
'phonenumber2' => '234-567-8901',
'phonenumber' => '123-456-7890',
'rentorown' => 'rent',
'zipcode' => '12345',
'Addr' => '1 main st.'
},
'Jane Doe' => {
'zipcode' => '54321',
'Addr' => '10 Downing st.',
'phonenumber' => '987-65-4321',
'rentorown' => 'own'
}
};



Chris Charley
User

Feb 22, 2016, 6:45 PM

Post #5 of 9 (2243 views)
Re: [rlovell6] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

To get the correct results when there are missing fields, in your case phonenumber2, I've made the following changes.

  • I moved the increment of the counter, $I, to the first captured field. It was only getting incremented when a phone2 was found.

  • Instead of pushing to the arrays, the value is assigned to the array with the index number $i. This keeps the records in sync

  • I changed the 'if' conditionals to 'elsif' because for any 1 line, there can only be 1 possible match,

  • The check for 'phone2' has to come before the check for 'phone'. Otherwise, 'phone' would also match 'phone2'

  • I surrounded the 'Name' attribute with quotes. If there's a comma in the 'Name' field, you would be unable to parse your output file after it was created. (You should be using a CSV parser to parse the output file after it is created.)


  • In the out put section, I also made a couple of changes.

  • I changed the ', ' to ',' (no space after the comma). Without the change, parsing would again be difficult or impossible.

  • I used the 'defined or', '//', operator. When there is an empty field, like 'phone2' in a record, this would silence any 'warnings' about undefined values when printing. In this case, if the value is 'undefined', it passes the empty string '' instead.


  • The program here reads from the __DATA__ file at the end of the file (where the sample records are located). You can copy and paste the program including the __DATA__ section and run it to see the results.


    Code
    #!/usr/bin/perl 
    use strict;
    use warnings;

    my @Name;
    my @Zip;
    my @Phone;
    my @Phone2;

    my $i = -1;

    while (my $attribute = <DATA>) {
    chomp $attribute;

    if ($attribute =~ /Name/)
    {
    $i++;
    $Name[$i] = "\"$attribute\"";
    }
    elsif ($attribute =~ /zipcode/)
    {
    $Zip[$i] = $attribute;

    }
    elsif ($attribute =~ /phonenumber2/)
    {
    $Phone2[$i] = $attribute;
    }
    elsif ($attribute =~ /phonenumber/)
    {
    $Phone[$i] = $attribute;

    }
    }


    my $n = 0;

    do {
    print $Name[$n];
    print ",";
    print $Zip[$n] // '';
    print ",";
    print $Phone[$n] // '';
    print ",";
    print $Phone2[$n] // '', "\n";
    } while($n++ < $i);



    __DATA__
    Customer record
    Name = John Doe
    Addr = 1 main st.
    zipcode = 12345
    phonenumber = 123-456-7890
    phonenumber2 = 234-567-8901
    rentorown = rent

    Customer record
    Name = Mark Doe, Jr.
    Addr = 1 main st.
    zipcode = 78945
    phonenumber = 123-456-7890
    phonenumber2 = 234-567-8901
    rentorown = rent

    Customer record
    Name = Jane French
    Addr = 1 main st.
    zipcode = 12021
    phonenumber = 123-456-7890

    Customer record
    Name = Robert Last
    Addr = 1 main st.
    phonenumber = 123-456-7890
    rentorown = rent

    And here is the output from this program.

    Code
    "Name = John Doe",zipcode = 12345,phonenumber = 123-456-7890,phonenumber2 = 234-567-8901 
    "Name = Mark Doe, Jr.",zipcode = 78945,phonenumber = 123-456-7890,phonenumber2 = 234-567-8901
    "Name = Jane French",zipcode = 12021,phonenumber = 123-456-7890,
    "Name = Robert Last",,phonenumber = 123-456-7890,


    I am attaching 2 files. One is a solution a bit different than yours and the second is the out put it generated.

    Update: Changed the program t44.pl to use Text::CSV


    (This post was edited by Chris Charley on Feb 24, 2016, 10:10 AM)
    Attachments: output.txt (0.19 KB)
      t33.pl (1.11 KB)


    rlovell6
    Novice

    Feb 22, 2016, 7:41 PM

    Post #6 of 9 (2232 views)
    Re: [FishMonger] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

    Thank you very much for the help. Unfortunately I am out of the office the rest of the week and not able to try this out until next week, but I feel confident that your recommendations will solve my problem! Thank you very much for your assistance and when I do get to try it I'll update this thread with the results for the next person who searches it!


    rlovell6
    Novice

    Feb 22, 2016, 7:44 PM

    Post #7 of 9 (2230 views)
    Re: [Chris Charley] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

    Thank you very much for the help. Unfortunately I am out of the office the rest of the week and not able to try this out until next week. Your suggestion as well as the other reply I got both seem to be good solutions and seeing as I'll be doing a lot more Perl programming in the future I'm sure both will prove extremely helpful. I want to thank you very much for your assistance and I will up date this thread next week after I've had a chance to try them out.


    rlovell6
    Novice

    Mar 7, 2016, 9:48 AM

    Post #8 of 9 (2159 views)
    Re: [Chris Charley] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

    Sorry for the delay in updating, but as always, life gets in the way of plans! Anyway, thank you, this worked perfect and I'm now using this.


    rlovell6
    Novice

    Mar 7, 2016, 9:50 AM

    Post #9 of 9 (2158 views)
    Re: [FishMonger] Parsing text file using perl similarly named fields are not parsed correctly [In reply to] Can't Post

    Sorry for the delay, this solution worked as well, however I found another more flexible for what I was doing. But I was able to use this to solve another issue, so thank you very much for your assistance!

     
     


    Search for (options) Powered by Gossamer Forum v.1.2.0

    Web Applications & Managed Hosting Powered by Gossamer Threads
    Visit our Mailing List Archives