Re: Help Me!
by jwkrahn (Abbot) on Apr 10, 2011 at 04:23 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
Very good start! These pragmas should be at the beginning of every Perl program. (Note that it is spelled Perl, not PERL.)
open FILE, "/home/ajb004/Paradigms/roster.txt" or die $!;
You should usually use the three argument form of open and lexically scoped filehandles and you should probably include the file name in the error message so you know which file failed to open.
$_;
You have a variable in void context which should trigger a warning message.
$_ = $word;
s/_/ /g;
print "ID: $_\n";
Why are you modifying $_ in this loop when you could just use $word directly?
$word =~ s/_/ /g;
print "ID: $word\n";
And since you are also using $_ in the outer loop then this could cause problems in some situations so you should probably avoid using $_ if you can:
while ( my $line = <FILE> )
{
my @words = split /,/, $line;
foreach my $word ( @words )
{
$word =~ s/_/ /g;
print "ID: $word\n";
}
}
And if you are modifying single characters then the tr/// operator is usually more efficient than the s///g operator.
According to your explanation and data you probably need something like this:
#!/usr/bin/perl
use strict;
use warnings;
my $file = "/home/ajb004/Paradigms/roster.txt";
open my $FILE, '<', $file or die "Cannot open '$file' because: $!";
while ( my $line = <$FILE> )
{
chomp $line;
$line =~ tr/_/ /;
my ( $id, $name, $major, $email ) = split /,/, $line;
print <<TEXT;
ID: $id
Name: $name
Major: $major
Email: $email
TEXT
}
| [reply] [d/l] [select] |
|
|
You should usually use the three argument form of open and lexically scoped filehandles and you should probably include the file name in the error message so you know which file failed to open.
Actually, it's quite common that it doesn't matter whether one uses 2-arg, or 3-arg open. This is one of the cases.
As for the error message, considering the program only tries to open one file, with a fixed name, it should be bloody obvious which file failed to open. "Should include the file name" is a much too strong.
| [reply] |
|
|
The sooner one starts using safety nets like strictures, lexically scoped variables, full error messages and so on the more benefit one derives from their use and the more likely that such techniques will become habit. The time when such techniques are most useful is during the discovery stages of learning the language, not later on when one should know better in any case and has a better debugging toolkit to help sort problems out in any case.
While there is a balance between introducing too much and introducing good habits early, the OP (by accident or design) is already using strictures and checking the success of open, so introducing another related three safety net techniques seems reasonable.
True laziness is hard work
| [reply] |
Re: Help Me!
by GrandFather (Saint) on Apr 10, 2011 at 01:43 UTC
|
A for loop over the "words" is not going to do it for you. The array name should be words btw (there's probably more than one of them)! You can access individual words using their index (starting at 0) as $words[0] (for the ID) so you could print out the id using:
print "ID: $words[0]\n";
for example. You ought to be able to take it from there.
Out of curiosity, how did you get to the code you have already? There are some good things about it, and a couple of less good things. Using strictures is excellent. But you should be using the three parameter version of open and lexical file handles:
open my $inFile, '<', $filename or die "Can't open $filename: $!\n";
True laziness is hard work
| [reply] [d/l] [select] |
|
|
<HTML>
<HEAD>
<TITLE>Class Roster</TITLE>
</HEAD>
<BODY>
<TABLE>
<TR>
<TD>ID: 123456</TD>
<TD>Name: Suzie Smith</TD>
<TD>Major: Computer Science</TD>
<TD>Email: ssmith@uark.edu</TD>
<TD>Parking Fees Owing: $22.00</TD>
</TR>
<TR>
<TD>ID: 777777</TD>
<TD>Name: John Brown</TD>
<TD>Major: Computer Engineering</TD>
<TD>Email: jbrown@uark.edu</TD>
<TD>Parking Fees Owing: $0.00</TD>
</TR>
</TABLE>
</BODY>
</HTML>
| [reply] [d/l] |
|
|
I'd suggest first you play around with the code you have and understand it. Once you understand what you've got the rest is just fiddling with the details.
There are modules in CPAN that help generate correct HTML, but for the present probably the simplest approach is best.
Note that the indentation is not required for HTML, although it makes it easier for humans to validate.
True laziness is hard work
| [reply] |
|
|
But you should be using the three parameter version of open and lexical file handles
No, in this case, two parameter open, and a file glob is just fine.
Note for instance that lexical file handles have been with us since 5.000. It wasn't until they also got to be autovivifying that they got more popular.
I think it's for starters (actually, everyone) far more important to get their programs correct, before worrying about the nuances between 2-arg and 3-arg open, or globs and autovivifying filehandles.
| [reply] |
Re: Help Me!
by LanX (Saint) on Apr 10, 2011 at 01:43 UTC
|
print "ID: $_\n"; shouldn't be in the inner loop, better do
print "ID: $word[0]\n";
...
outside.
| [reply] [d/l] [select] |
Re: Help Me!
by locked_user sundialsvc4 (Abbot) on Apr 10, 2011 at 05:11 UTC
|
For what it may be worth, my good padewan, you may rest assured that your professor really does know exactly what (s)he is doing. Believe it or not, (if you persevere in this very-strange-feeling “swimming lesson”) you will emerge from this baptism, “enlightened.”
Do not hesitate to avail yourself of your instructor ... and bear in mind that (s)he (with deliberate purpose) expects and requires you to ... ask!
The most important matter ... and please, pay close attention to my words here ... is not whether you ask, but, exactly what it is that you eventually ask.
I apologize for sounding inscrutable here, and if you want to dismiss me as an absolute <!>hole ... please, go ahead. I don’t mind. The first computer program that I ever wrote, almost thirty years ago now:
-
Was eight lines long.
-
Took me six months to write. (“Computer science” college degrees did not yet exist. Heh.)
-
Had a bug in it. (Some things never change...)
I am not mocking you.
| |
Re: Help Me!
by Marshall (Canon) on Apr 10, 2011 at 20:34 UTC
|
I personally would not consider this a particularly good first assignment in Perl. So, in this case I don't mind giving some extra help.
Yes, you started out in a good way!! You do not need to "declare $_", it just always exists as the loop iterator unless you over-ride it which you did as with my $word. Perl has a number of magic variables like that. I put a comment in the code if I'm using an obscure one. I view $_ as Perl's variable and very seldom assign directly to it myself. I view it as good practice to use a variable like 'my $word' because it often adds value to the loop in terms of documentation. Here, $word is not much help but 'my $IP_address', 'my $customer' might mean more in other situations.
If you split on something other than the default regex which is /\s+/, you need to take into account what happens to the newline and the end of the input line. The Perl function chomp() removes that and works on Windows as well as Unix. Otherwise the '\n' winds up at the end of the last thing in the split().
The implementation question before you is: "how to get the right tag words in front of the right thing from the line". The input line has a fixed order to it. In many languages like C++, you would be thinking along the lines of using an indexed array of strings with this fixed text. Perl has many ways to eliminate indicies and in particular the 'C' style 'for(i=0;blah;blah){}' is particularly rare when processing text. Index operations and "off by one errors" are very common, if not the most common error in programming.
A Perl array can be viewed as a stack or a queue. You can push(),pop(),shift(),unshift() things on/off of a Perl array. Read about those functions - they a very fundamental to how Perl works (Perl variables are passed as a "stack" to a subroutine and they are shifted off - so you will see shift() often).
Instead of using indicies like $word[2] and $tag[2], below I show one way to do this without indicies at all! If you run out of tags before words, you will get an undefined value which will show up as an error since you are using "warnings" (which is an excellent idea).
So here is your code with very minimal changes. I used the DATA segment which is an already opened file handle and is often used in code like this rather than opening a separate file. I used a feature of Perl that allows documentation to be embedded in the code. You do not have to use either of these features, but they allowed me to have a single file with the code and the data and resulting printout. Just chalk this one up to "oh, its possible".
You will need to spew out some text before printing each line's block of html. That is a fixed header and footer. I think you can do that. You can use Perl print() or also printf(), or a "hereis" document.
#!/usr/bin/perl
use strict;
use warnings;
my @tag_template = ('ID', 'Name', 'Major', 'Email');
#open FILE, '/home/ajb004/Paradigms/roster.txt' or die $!;
while ( <DATA> )
{
chomp; ## needed to get rid of \n on e-mail address
my @word = split(/,/); #this is actually a regex
my @tags = @tag_template; #copy is not a big deal here
print "<TR>\n";
foreach my $word (@word)
{
$word =~ s/_/ /g;
my $tag = shift(@tags);
print " <TD>$tag: $word</TD>\n";
}
print "</TR>\n";
}
=Prints:
<TR>
<TD>ID: 123456</TD>
<TD>Name: Susie Smith</TD>
<TD>Major: Computer Science</TD>
<TD>Email: ssmith@usomewhere.edu </TD>
</TR>
<TR>
<TD>ID: 234567</TD>
<TD>Name: John Smith</TD>
<TD>Major: Computer Engineering</TD>
<TD>Email: jsmith@usomewhere.edu</TD>
</TR>
=cut
__DATA__
123456,Susie_Smith,Computer_Science,ssmith@usomewhere.edu
234567,John_Smith,Computer_Engineering,jsmith@usomewhere.edu
| [reply] [d/l] [select] |
|
|
my @tags = qw( ID Name Major Email );
#open FILE, '/home/ajb004/Paradigms/roster.txt' or die $!;
while ( <DATA> )
{
chomp; ## needed to get rid of \n on e-mail address
s/_/ /g; # this doesn't need to be in the inner loop
my %fields;
my @fields{ @tags } = split /,/; #this is actually a regex
print "<TR>\n";
foreach my $tag ( @tags )
{
print " <TD>$tag: $fields{$tag}</TD>\n";
}
print "</TR>\n";
}
| [reply] [d/l] |
|
|
Yes, but the OP is on his/her first Perl program. I don't see the need to use a hash in a first homework assignment - and especially not a hash slice which is certainly a more complex syntax than a simple hash assignment. Your code will not produce same order of output as the OP's code.
I figure that 2, one dimensional arrays are just fine for this first homework. Don't make it more complex than it needs to be!
updated: with strike-through.
| [reply] |
|
|
|
|
Re: Help Me!
by Swalif (Scribe) on Apr 10, 2011 at 02:13 UTC
|
use strict;
use IO::File;
my $file = new IO::File('file.txt','r') or die"Error can't open file";
foreach my $line ($file->getlines)
{
my ($id, $name, $major, $email) = split(',',$line);
chomp $email;
}
| [reply] [d/l] |
|
|
| [reply] |
|
|
Is there a problem to provide another solution?
So how do you know that the later code is not easy to read and learn ?
| [reply] |
|
|
|
|
|
|
|