Re: Perlish while loop
by CountZero (Bishop) on Jul 16, 2009 at 06:21 UTC
|
use File::Basename;
# ...
while (<$fh>) {
chomp;
if (/^M/) {
my $filename = fileparse($_);
# ...
}
}
It has as an additional benefit that it takes care of the different file-path separators on Unix, Windows, Mac, VMS, ..., making your script more compatible with different OSs.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] [d/l] |
Re: Perlish while loop
by rovf (Priest) on Jul 16, 2009 at 08:33 UTC
|
If you know you will stick with these three files (people, animal, msi), it's OK; but if you think that maybe the files to check might change, or will become more, you might want to set up a table of valid filenames,
my %filenames = (
'people.pdf' => 'People',
'setup.msi' => 'MSI',
# etc.
)
In your loop, you would check whether $filename occurs in %keys %filenames, and if it does, removes it from %filenames. After the loop, you just have to print values %filenames to list the names of files which haven't been found. This will be a lot easier to maintain.
--
Ronald Fischer <ynnor@mm.st>
| [reply] [d/l] [select] |
Re: Perlish while loop
by GrandFather (Saint) on Jul 16, 2009 at 10:53 UTC
|
There are many ways to refactor that code to make it easier to maintain. If the work to be done is really as light weight as is indicated then I'd tend toward a light weight object approach:
use strict;
use warnings;
my $obj = bless {};
$obj->processLine ($_) while <DATA>;
$obj->report ();
sub processLine {
my ($self, $line) = @_;
return if $line !~ /^M/;
chomp $line;
my $filename = (split '/', $line)[-1];
return if ! defined $filename;
$self->{files}{$filename} ||= $line;
}
sub report{
my ($self) = @_;
print "People not found\n" if ! exists $self->{files}{'people.pdf'
+};
print "animal not found\n" if ! exists $self->{files}{'animal.pdf'
+};
print "MSI not found\n" if ! exists $self->{files}{'setup.msi'};
}
__DATA__
M/people.pdf
M/wiggles.pdf
M/setup.msi
Prints:
animal not found
which scales nicely as you need to detect more or fewer file names, but could easily be changed to use a dispatch table in the 'report' section to handle more work for each found file.
True laziness is hard work
| [reply] [d/l] [select] |
Re: Perlish while loop
by dsheroh (Monsignor) on Jul 16, 2009 at 11:42 UTC
|
Perl allows postfix flow control, which would tighten this up a bit. Personally, I also find this version much more readable, but there are those who would disagree:
...
$people = 1 if ($filename eq 'people.pdf');
$animal = 1 if ($filename eq 'animal.pdf');
$msi = 1 if ($filename eq 'setup.msi');
}
}
print "People not found\n" unless defined $people;
print "animal not found\n" unless defined $animal;
print "MSI file not found\n" unless defined $msi;
...
rovf's suggestion with using a hash to store the mapping of filenames to file descriptions is definitely the way to go for longer-term maintenance, since it allows you to expand the range of things you're looking for by simply adding a new hash entry, turning this into:
my %filenames = (
people.pdf => 'Person',
animal.pdf => 'animal',
setup.msi => 'MSI file',
);
...
for (keys %filenames) {
delete $filenames{$_} if $filename eq $_;
}
}
}
for (values %filenames) {
print "$_ not found\n";
}
...
| [reply] [d/l] [select] |
|
|
for (keys %filenames) {
delete $filenames{$_} if $filename eq $_;
}
instead of simply
delete $filenames{$filename};
and just not worry about the cases where the $filename wasn't one of the ones that you're interested in? keys has to build a list, then that has to be traversed, and each value compared. I could understand
if ( exists $filenames{$filename} ) {
delete $filenames{$filename};
}
especially if there is a chance that %filenames is tied to something big and slow. Is there something that I overlooked?
- doug | [reply] [d/l] [select] |
|
|
Honestly? Because I was translating from the non-hash version above it and just copied the structure without thinking about it. Thanks for catching that!
| [reply] |
Re: Perlish while loop
by Anonymous Monk on Jul 16, 2009 at 06:17 UTC
|
You shouldn't make it more compact than this; enjoy!
while (<$fh>) {
if (/^M/) {
my @output = split('/');
my $filename = $output[-1];
chomp($filename);
if ( $filename eq 'people.pdf' ) {
$people = "1";
}
if ( $filename eq 'animal.pdf' ) {
$animal = "1";
}
if ( $filename eq 'setup.msi' ) {
$msi = "1";
}
}
}
if ( !( defined $people ) ) {
print "People not found\n";
}
if ( !( defined $animal ) ) {
print "animal not found\n";
}
if ( !( defined $msi ) ) {
print "MSI file not found\n";
}
exit;
| [reply] [d/l] |
Re: Perlish while loop
by spazm (Monk) on Jul 16, 2009 at 07:25 UTC
|
a bit tighter. Basename is probably better than the s,.*/,,
as pointed out above.
while (<$fh>)
{
if (/^M/) #What is this ?
{
chomp;
my $filename = $_;
$filename s,.*/,,; #strip off leading path info
$seen->{$filename}++
if( $filename =~ /pdf/ || $filename =~ /msi/)
}
}
if (! exists $seen->{'people.pdf'} )
{
print "People not found\n";
}
if (! exists $seen->{'animal.pdf'} )
{
print "animal not found\n";
}
if (! exists $seen->{'setup.msi'))
{
print "MSI file not found\n";
}
exit;
| [reply] [d/l] |
|
|
Your Solution is another new thing for me but I am bit paranoid about using "$seen", as looking at your code you are using $seen as a hash.
But while declaring if I define "seen" as
my %seen
That give me error
but if I declare it as a $seen variable it works
and that makes me confuse.
Any Suggestion?Please.
Cheers
| [reply] [d/l] |
Re: Perlish while loop
by doug (Pilgrim) on Jul 16, 2009 at 19:35 UTC
|
use strict;
use warnings;
my %saw = ();
while ( <DATA> ) {
next unless ( m#^M.*/([^/]+)# );
my $filename = $1;
chomp $filename;
$saw{$filename} = 1;
}
print "People not found\n." unless ( $saw{'people.pdf'} );
print "animal not found\n" unless ( $saw{'animal.pdf'} );
print "MSI file not found\n" unless ( $saw{'setup.msi'} );
__DATA__
M/people.pdf
M/wiggles.pdf
M/setup.msi
You do twice as many "if"s as necessary: just store everything and do the checks once.
- doug | [reply] [d/l] |