LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Closed Thread
  Search this Thread
Old 11-11-2011, 05:01 PM   #1
jmc1987
Member
 
Registered: Sep 2009
Location: Oklahoma
Distribution: Debian, CentOS, windows 7/10
Posts: 893

Rep: Reputation: 119Reputation: 119
Trying to get Understanding on filehandle and split function in Perl


Okay I'm still working on my perl studies when I can and I am a little confused on how this is working.

PHP Code:
#!/usr/bin/perl -w

open(PH"customers.txt") or die "Cannot open customers.txt: $!\n";
while(<
PH>) {
    
chomp;
    (
$number$email) = (split(/\s+/, $_))[1,2];
    
$Phone{$number}=$_;
    
$Email{$email}=$_;
}
close(PH);

print 
"Type 'q' to exit\n";
while (
1) {
    print 
"\nNumber? ";
    
$number = <STDIN>; chomp ($number);
    
$address "";
    if (! 
$number) {
        print 
"E-Mail? ";
        
$address = <STDIN>; chomp $address;
    }
    
    
next if (! $number and ! $address);
    
last if ($number eq 'q' or $address eq 'q');
    
    if (
$number and exists $Phone{$number} ) {
        print 
"Customer: $Phone{$number}\n";
        
next;
    }
    if (
$address and exists $Email{$address} ) {
        print 
"Customer: $Email{$address}\n";
        
next;
    }
    print 
"Customer record not found. \n";
    
next;
}
print 
"\nAll done.\n"
customers.txt
Code:
Smith,John    (248)-555-9430 jsmith@aol.com
Hunter,Apryl    (810)-555-3029 april@showers.org
Stewart,Pat    (405)-555-8710 pats@starfleet.co.uk
Ching,Iris    (305)-555-0919 iching@zen.org
Doe,John    (212)-555-0912 jdoe@morgue.com
Jones,Tom    (312)-555-3321 tj2342@aol.com
Smith,John    (607)-555-0023 smith@pocahontas.com
Crosby,Dave    (405)-555-1516 cros@csny.org
Johns,Pam    (313)-555-6790 pj@sleepy.com
Jeter,Linda    (810)-555-8761 netless@earthlink.net
Garland,Judy    (305)-555-1231 ozgal@rainbow.com
Now what I have to do is modify this code to allow me to search by a name and I'm not quite understanding on how the names are stored in the hashes.

Now this is where I'm not quite understanding on line 4,5,and 6.
PHP Code:
open(PH"customers.txt") or die "Cannot open customers.txt: $!\n";
while(<
PH>) {
    
chomp;
    (
$number$email) = (split(/s+/, $_))[1,2];
    
$Phone{$number}=$_;
    
$Email{$email}=$_;
}
close(PH); 
Now from what I understand
line 1: open customers.txt for reading
line 2: begins the loop untill it run out of lines in customers.txt
line3: removes all the new lines off of each line
line 4: take something like
Quote:
Smith,John (248)-555-9430 jsmith@aol.com
($number, $email) = (split(/s+/, $_))[1,2];
now from what I understand the split is splitting on pattern whie spaces to the end of line and [1,2] Is 1 for the number and 2 for the email. So does that mean 0 would be for name?

Really I just need a better explaination on how line 2-6 work out so I can modify the code to search by name.
 
Old 11-11-2011, 05:33 PM   #2
lesleyb
Member
 
Registered: Sep 2003
Distribution: Debian, OpenBSD 3.9 & 3.7
Posts: 79

Rep: Reputation: 17
You might need to get [0] , split that on the , amd then match on the result
 
Old 11-11-2011, 07:11 PM   #3
jmc1987
Member
 
Registered: Sep 2009
Location: Oklahoma
Distribution: Debian, CentOS, windows 7/10
Posts: 893

Original Poster
Rep: Reputation: 119Reputation: 119
Building a name search function into perl program

grr I can't edit the title of the post.

Okay I got this code allow me to search by name but I have to put a whitespace in front of all lines in customers.txt

PHP Code:
#!/usr/bin/perl -w

open(PH"customers.txt") or die "Cannot open customers.txt: $!\n";
while(<
PH>) {
    
chomp;
    (
$name$number$email) = (split(/\s+/, $_))[1,2,3];
    
$Name{$name}=$_;
    
$Phone{$number}=$_;
    
$Email{$email}=$_;
}
close(PH);

print 
"Type 'q' to exit\n";
while (
1) {
    print 
"\nNumber? ";
    
$number = <STDIN>; chomp ($number);
    
$address "";
    
$name "";
    if (! 
$number) {
        print 
"E-Mail? ";
        
$address = <STDIN>; chomp $address;
        
        if ( ! 
$address) {
            print 
"Name? ";
            
$name = <STDIN>; chomp $name;
        }
        
    }
    
    
next if (! $number and ! $address and ! $name);
    
last if ($number eq 'q' or $address eq 'q' or $name eq 'q');
    
    if (
$number and exists $Phone{$number} ) {
        print 
"Customer: $Phone{$number}\n";
        
next;
    }
    if (
$address and exists $Email{$address} ) {
        print 
"Customer: $Email{$address}\n";
        
next;
    }
    if (
$name and exists $Name{$name} ) {
        print 
"Customer: $Name{$name}\n";
        
next;
    }
    print 
"Customer record not found. \n";
    
next;
}
print 
"\nAll done.\n"
But if I was to be graded on the modification I don't think I would pass because the exercise says
Quote:
Modify the Customer program to allow a search by name, Because you cannot use name as a hash key, you need to search through the values in the hash.
So I guess I'm back to figure it out how the book says to.

Last edited by jmc1987; 11-11-2011 at 07:27 PM.
 
Old 11-12-2011, 06:22 AM   #4
SecretCode
Member
 
Registered: Apr 2011
Location: UK
Distribution: Kubuntu 11.10
Posts: 562

Rep: Reputation: 102Reputation: 102
Code:
($name, $number, $email) = (split(/s+/, $_))[1,2,3];
Close. Firstly you need /\s+/ to split on spaces - currently you are splitting in literal 's'. Secondly, arrays are indexed from zero so you need [0,1,2] ... but since this is the entire array you don't in fact need to take a slice.
Code:
($name, $number, $email) = (split(/\s+/, $_));
Now, you can't use name as a hash key because name might not be unique (and isn't unique in the sample data!). This means that your new code will fail on 'Smith,John'.

So you need something like
Code:
$Names{$number} = $name;
in your file-read loop, and
Code:
    if ($name) {
    	my $found = 0;
    	while (my ($tryphone, $tryname) = each(%Names)) {
    	    if ($name eq $tryname) { 
    	        print "Customer: $Phone{$tryphone}\n"; 
	        $found = 1;
    	    }
    	}
        next if $found;
    }
in your interactive loop. Read about iterating over hashes: iterate through a hash | Perl HowTo and lots of other sites.

The original code uses email and phone as keys for two different hashes. I would say this is bad because you could have two customers with the same phone number (different people in the same building). Anyway it makes more sense to have a single hash for a single object - but you'd need to get to grips with hashes of hashes.

Last edited by SecretCode; 11-12-2011 at 06:24 AM.
 
1 members found this post helpful.
Old 11-12-2011, 10:57 AM   #5
jmc1987
Member
 
Registered: Sep 2009
Location: Oklahoma
Distribution: Debian, CentOS, windows 7/10
Posts: 893

Original Poster
Rep: Reputation: 119Reputation: 119
Actually I got it to work last night with this
PHP Code:
#!/usr/bin/perl -w

open(PH"customers.txt") or die "Cannot open customers.txt: $!\n";
while(<
PH>) {
    
chomp;
    (
$name$number$email) = (split(/\s+/, $_))[0,1,2];
    
$Name{$name}=$_;
    
$Phone{$number}=$_;
    
$Email{$email}=$_;
}
close(PH);

print 
"Type 'q' to exit\n";
while (
1) {
    print 
"\nNumber? ";
    
$number = <STDIN>; chomp ($number);
    
$address "";
    
$name "";
    if (! 
$number) {
        print 
"E-Mail? ";
        
$address = <STDIN>; chomp $address;
        
        if (! 
$address) {
        print 
"Name? ";
        
$name = <STDIN>; chomp $name;
        }        
    }
    
    
next if (! $number and ! $address and ! $name);
    
last if ($number eq 'q' or $address eq 'q' or $name eq 'q');
    
    if (
$number and exists $Phone{$number} ) {
        print 
"Customer: $Phone{$number}\n";
        
next;
    }
    if (
$address and exists $Email{$address} ) {
        print 
"Customer: $Email{$address}\n";
        
next;
    }
    if (
$name and exists $Name{$name} ) {
        print 
"Customer: $Name{$name}\n";
        
next;
    }
    print 
"Customer record not found. \n";
    
next;
}
print 
"\nAll done.\n"
customers.txt
Code:
Smith,John    (248)-555-9430 jsmith@aol.com
Hunter,Apryl    (810)-555-3029 april@showers.org
Stewart,Pat    (405)-555-8710 pats@starfleet.co.uk
Ching,Iris    (305)-555-0919 iching@zen.org
Doe,John    (212)-555-0912 jdoe@morgue.com
Jones,Tom    (312)-555-3321 tj2342@aol.com
Smith,John    (607)-555-0023 smith@pocahontas.com
Crosby,Dave    (405)-555-1516 cros@csny.org
Johns,Pam    (313)-555-6790 pj@sleepy.com
Jeter,Linda    (810)-555-8761 netless@earthlink.net
Garland,Judy    (305)-555-1231 ozgal@rainbow.com
So I know longer needed the whitespaces in front of each line in customers.txt. But I will try the while loop to search like you showed. I do see your point where I don't need the [0,1,2] since I'm returning the whole thing into a hash.

Thanks for the help

Last edited by jmc1987; 11-12-2011 at 10:58 AM.
 
Old 11-12-2011, 04:07 PM   #6
lesleyb
Member
 
Registered: Sep 2003
Distribution: Debian, OpenBSD 3.9 & 3.7
Posts: 79

Rep: Reputation: 17
You are retrieving the components of the line as a list construct. See http://perldoc.perl.org/perldata.html for more info on lists.

Also see http://perldoc.perl.org/perlvar.html for a better understanding of $_.



You really need to use one hash to contain all the elements of a customer's record.
And then build an array of hashes like this :

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

my @CustomerRecords;  
open(PH, "customers.txt") or die "Cannot open customers.txt: $!\n";
while(<PH>) {
    chomp;
    my %CustomerRecord;
    ($name, $number, $email) = (split(/s+/, $_));
    ## TODO:  split $name on the ',' character and re-order it 
    ## before assigning to the 'Name' element of the temporary hash
    $CustomerRecord{'Name'} = $name;
    $CustomerRecord{'Number'} = $number;
    $CustomerRecord{'Email'} = $email;
    push @CustomerRecords, { %CustomerRecord }; 
}
close(PH);
At this point, $CustomerRecords[0]{'Name'} will contain the first John Smith and $CustomerRecords[6]{'Name'}
the second occurrence of John Smith.

See http://perldoc.perl.org/perldsc.html which discusses generating arrays of hashes.

Each element of your final array will be a hash (aka an associative array) containing one person's details.
Then rework the remainder of your code to use these data structures.

Good luck
 
Old 11-14-2011, 03:09 AM   #7
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
BTW.

Code:
split(/s+/, $_
Is not how one does split on whitespace. Even though it is correct.
(It requires more typing, most un-perl)
Code:
split
is enough


split by default splits $_ on whitespace.
And furthermore, to split on whitespace you only need to do
split " " as this is a special case in perl.

split

Last edited by bigearsbilly; 11-14-2011 at 03:13 AM.
 
Old 11-14-2011, 02:11 PM   #8
SecretCode
Member
 
Registered: Apr 2011
Location: UK
Distribution: Kubuntu 11.10
Posts: 562

Rep: Reputation: 102Reputation: 102
Quote:
Originally Posted by jmc1987 View Post
Actually I got it to work last night with this
...
What does your code return when you give it the name Smith,John? There are two Smith,John customers and it should return both of them!
 
Old 11-25-2011, 10:00 PM   #9
jmc1987
Member
 
Registered: Sep 2009
Location: Oklahoma
Distribution: Debian, CentOS, windows 7/10
Posts: 893

Original Poster
Rep: Reputation: 119Reputation: 119
Quote:
Originally Posted by SecretCode View Post
What does your code return when you give it the name Smith,John? There are two Smith,John customers and it should return both of them!
Okay I see what your saying. I'm actually rewriting this code now but the keys is overwriting so technically I am losing hashes.
 
Old 11-26-2011, 05:09 AM   #10
markush
Senior Member
 
Registered: Apr 2007
Location: Germany
Distribution: Slackware
Posts: 3,979

Rep: Reputation: Disabled
Hi,

you are losing hashes if you don't create a new hash for every record! Otherwise you will always use the same hash and push the same hash with new data onto the array which results in an array with all entries the same.

The normal way to use an array of hashes in perl is to use references to hashes. This means you create a new hash for every record and push a reference to the new hash onto the array.

Markus
 
Old 11-27-2011, 06:31 AM   #11
lesleyb
Member
 
Registered: Sep 2003
Distribution: Debian, OpenBSD 3.9 & 3.7
Posts: 79

Rep: Reputation: 17
Quote:
Originally Posted by jmc1987 View Post
Okay I see what your saying. I'm actually rewriting this code now but the keys is overwriting so technically I am losing hashes.
You're not 'losing' the hash, you are overwriting it.

The code I gave earlier declares a new hash for each record, from within the file reading loop. After all, you've one record per line and you need a hash for each record, yes? Plus you then need to push the hash
Code:
push @CustomerRecords, { %CustomerRecord };
, or its reference,
Code:
 push @CustomerRecords, \%CustomerRecord ;
on to the array.
You could just use a reference within the loop,
Code:
while(<PH>) {
    chomp;
    my $CustomerRecord;
    ($name, $number, $email) = split;
    ## TODO:  split $name on the ',' character and re-order it 
    ## before assigning to the 'Name' element of the temporary hash
    $CustomerRecord->{'Name'} = $name;
    $CustomerRecord->{'Number'} = $number;
    $CustomerRecord->{'Email'} = $email;
    push @CustomerRecords, { $CustomerRecord }; 
}
But your accessors will change to
Code:
$CustomerRecords[0]->{'Name'}
If you encapsulate this effort into a subroutine and return a reference to the array you have generated, now containing a list of hashes. then the accessor will change to
Code:
$CustomerRecords->[0]->{'Name'}
 
Old 11-27-2011, 02:31 PM   #12
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by lesleyb View Post
You're not 'losing' the hash, you are overwriting it.
...
The OP has already started a new thread about scope (in Perl).
 
Old 11-28-2011, 01:31 AM   #13
jmc1987
Member
 
Registered: Sep 2009
Location: Oklahoma
Distribution: Debian, CentOS, windows 7/10
Posts: 893

Original Poster
Rep: Reputation: 119Reputation: 119
Quote:
Originally Posted by Sergei Steshenko View Post
The OP has already started a new thread about scope (in Perl).
Yea sorry lost this thread but the new thread is here

http://www.linuxquestions.org/questi...41#post4535941

Can a moderator perhaps lock this thread so all new post go to the other?
 
Old 11-29-2011, 09:34 PM   #14
crabboy
Senior Member
 
Registered: Feb 2001
Location: Atlanta, GA
Distribution: Slackware
Posts: 1,821

Rep: Reputation: 121Reputation: 121
done
 
  


Closed Thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
new line matching in PERL in a split function gaynut Programming 2 09-02-2008 12:02 PM
Need help using split() function in php orfiyus Programming 7 06-21-2007 02:19 PM
Perl filehandle problems DanTaylor Programming 8 01-27-2006 04:57 PM
PERL Q, split function and reg expressions amytys Programming 1 12-08-2004 10:54 AM
Perl exec function in linux (and system-function) nazula Programming 1 04-19-2004 12:21 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 01:11 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration