Forum Moderators: coopster & phranque

Message Too Old, No Replies

Separating information in a text file w/ Perl

I am very new at this so forgive my dumb Ques

         

Lennie

1:28 pm on Apr 26, 2003 (gmt 0)

10+ Year Member



I have a text file for which I write the names, age, and email address of users. I wrote to the file with:

open(entry,">members.txt");
print entry "$name¦$age¦$email"
close(entry)

However, I don't know how to retrieve the information back into variables.

For example, if I use
open(entry,"members.txt");

What do I do next to make it take the fields of the line back into the variables $name, $age, and $email?

ShawnR

2:19 pm on Apr 26, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Writing:
========
  • With '>' you are writing the file afresh, not appending new record to the end of it. You can append with '>>'
  • You should check to make sure the open was successful
  • To have each record on a new line, add \n to the string you are printing
  • Don't forget the semicolons at the end of your statements
  • It is a convention that filehandles (i.e. 'entry') are upper case (ENTRY). Perl doesn't care, but humans who read the code find it easier to understand your code if you follow the convention.

Reading:
========
After "open(ENTRY,"members.txt");", you can read all the lines of the file into an array as follows:

@all_lines_in_file = <ENTRY>;

or you can read them and process them one at a time (using split to extract ) as follows:

while (<ENTRY>) {
# Now $_ contains the line
($name, $age, $email) = split(/\¦/);
# Now process the variables
}

Shawn

Lennie

5:40 pm on Apr 26, 2003 (gmt 0)

10+ Year Member



Remember I'm a beginner, so it takes a minutes to understand. Here is my modification in code per the response; however, I am getting an error.

#!/usr/bin/perl
$member = "member.txt";
open(ENTRY,"$member");
while (<ENTRY>) {
($name, $age, $email) = split(/\¦/);
}
close(ENTRY);
print "Content-Type: text/html\n\n";
print "Test $name\n"; ##Prints to html page

I thought this code would print the last name in the list to my page, but I guess not. How do I get the code to selectively print the first name, last name or any other name in the list. Here is my database

Lennie¦30¦lfulwood@att.net¦
John¦23¦jtry@att.net¦
Pamela¦22¦pdavis22@hotmail.com

andreasfriedrich

6:08 pm on Apr 26, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The code itself is fine. Just note that you do not need the double quotes in
[url=http://www.perldoc.com/perl5.8.0/pod/func/open.html]open[/url](ENTRY,"$member");
.

It would be helpful if you´d post the error message you get. If you have access to the webserver´s error log there will be some useful information about the error compared to what it spits out to the browser.

If you don´t have access to the error log, then add this to your code, which causes fatal errors to be output to the browser.


#!/usr/bin/perl [perl.com] -w
BEGIN {
use [perldoc.com] CGI::Carp [perldoc.com] q [perldoc.com]w(fatalstobrowser);
}
use [perldoc.com] strict [perldoc.com];

If you use [perldoc.com] strict [perldoc.com] you will need to quote 'ENTRY' in your open [perldoc.com] and close [perldoc.com] calls.

Andreas

Lennie

6:16 pm on Apr 26, 2003 (gmt 0)

10+ Year Member



I apologize, the error was typographical in my html; however, it did not print the last name in the file. And of course, I don't know how to make it print the first or second record.

andreasfriedrich

6:50 pm on Apr 26, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



No need to apologize Lenni :).

The script prints Test Pamela for me.

To print the nth name simply loop n times and then break out of the while loop using last [perldoc.com]:


my $count = 0;
my $nth_name= 2;
my ($name, $age, $email) = ('', '', '');
while (<ENTRY>) {
($name, $age, $email) = split [perldoc.com](/\¦/);
$count++;
last [perldoc.com] if $count == $nth_name;
}

Andreas

Lennie

9:50 pm on Apr 26, 2003 (gmt 0)

10+ Year Member



That's exacly what I needed, thank you again.

ShawnR

4:20 am on Apr 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



"...use CGI::Carp qw(fatalstobrowser); ..."

I love Andreas' posts... I always learn something new!

Another way to do it, which allows you to print the last one or second last etc, without knowing how many records there are, is below. (Already sent to Lennie by sticky, but just in case anyone else is looking to do the same thing in future, and does a search):

#!/usr/bin/perl
open(entry, "member.txt");
print "Content-Type: text/html\n\n";
@all_members = <entry>;

# 1st one:
($name, $age, $email) = split(/\¦/, $all_members[0] );
print "Test $name\n";

# 2nd one:
($name, $age, $email) = split(/\¦/, $all_members[1] );
print "Test $name\n";

# last one
($name, $age, $email) = split(/\¦/, $all_members[$#all_members] );
print "Test $name\n";

# 2nd last one
($name, $age, $email) = split(/\¦/, $all_members[$#all_members - 1] );
print "Test $name\n";

(Untested...)

andreasfriedrich

12:00 pm on Apr 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks Shawn :)

Just note that the function is called fatalsToBrowser not fatalstobrowser.

Slurping in the whole database is ok for small files. However, if you do not know the size of the database file or you want your script to scale well, then you might want to avoid this approach.

The DB_File [search.cpan.org] module lets you tie [perldoc.com] a text file to an array. In similar fashion you can use it to tie [perldoc.com] a database to a hash. To store more complex records you may want to use the MLDBM [search.cpan.org] module.

Flat Text File Tied To Array

This allows you to use array methods like push [perldoc.com], shift [perldoc.com], unshift [perldoc.com], pop [perldoc.com], and splice [perldoc.com] to manipulate the flat text file. Each line is treated as an element in your array.


#!/usr/bin/Perl [perl.com] -w
#
use [perldoc.com] strict [perldoc.com];
use [perldoc.com] CGI::Carp [perldoc.com] qw(fatalsToBrowser);
use [perldoc.com] DB_File;
#
my $filename = "member.txt";
#
print [perldoc.com] "Content-Type: text/html\n\n";
#
my @db;
tie [perldoc.com] @db, 'DB_File', $filename, O_RDWR¦O_CREAT, 0666, $DB_RECNO
or die [perldoc.com] "Cannot open file '$filename': $!\n";
#
print [perldoc.com] "First element: @{[(split(/\¦/, $db[0]))[0]]}<br>" if $db[0];
print [perldoc.com] "Last element: @{[(split(/\¦/, $db[-1]))[0]]}<br>";
print [perldoc.com] "2nd last element: @{[(split(/\¦/, $db[-2]))[0]]}<br>";
#
push [perldoc.com] @db, q{Aaron¦15¦aaron@webmasterworld.com};
print [perldoc.com] "Last element: @{[(split(/\¦/, $db[-1]))[0]]}<br>";
#
untie [perldoc.com] @db;

DBM File Tied To Hash

This allows you to easily store, access, and manipulate complex records in a database file. In the example below we store the member data for each member in an anonymous array. These arrays may be accessed via the persons username.

To change any member data you need to first assign the array reference to a temporary variable, make the changes and then assign the reference back to the member. See the code below for an example that changes Aaron´s age.


#!/usr/bin/Perl [perl.com] -w
#
use [perldoc.com] strict [perldoc.com];
use [perldoc.com] CGI::Carp [perldoc.com] q [perldoc.com]w(fatalsToBrowser);
use [perldoc.com] MLDBM qw(DB_File Storable);
#
my $filename = "member.dat";
#
my %db;
tie [perldoc.com] %db, 'MLDBM', $filename, O_RDWR¦O_CREAT, 0666
or die [perldoc.com] "Cannot open file '$filename': $!\n";
#
$db{Aaron} = ['Aaron Carter', 15, 'aaron@webmasterworld.com'];
$db{Lennie} = ['Lennie Last', 30, 'lennie@lennie.com'];
#
print [perldoc.com] '<br>Members:<br>', join '<br>', keys %db;
#
print [perldoc.com] "<br>Age Aaron: ", $db{Aaron}->[1];
#
print [perldoc.com] "<br>First element: @{[$db{(keys [perldoc.com] %db)[0]}->[0]]}<br>";
print [perldoc.com] "Last element: @{[$db{(keys [perldoc.com] %db)[-1]}->[0]]}<br>";
#
my $temp = $db{Aaron};
$temp->[1]++;
$db{Aaron} = $temp;
#
untie [perldoc.com] %db;

Andreas

ShawnR

12:51 pm on Apr 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks Andreas

"... fatalsToBrowser not fatalstobrowser ...
... Yes, I discovered that when I tried it... but once I had your hint to use GCI::Carp, that part was easy.

So why the @{ and } rather than $ in @{[(split(/\¦/, $db[0]))[0]]} and other similar lines?

Shawn

andreasfriedrich

1:38 pm on Apr 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The only two ways to interpolate the results of arbitrary expressions into a double quoted string are to use either
@{[ arbitrary expression ]}
or
${\( arbitrary expression )}
. The first approach dereferences the reference to the anonymous array that contains the data that we want to interpolate into the string. The second approach uses a scalar reference instead.

Andreas

ShawnR

2:22 pm on Apr 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



OK, thanks.