perl split on empty file
I have basically the following perl I'm working with:
open I,$coupon_file or die "Error: File $coupon_file will not Open: $! \n";
while (<I>) {
$lctr++;
chomp;
my @line = split/,/;
if (!@line) {
print E "Error: $coupon_file is empty!\n\n";
$processFile = 0; last;
}
}
I'm having trouble determining what the split/,/ function is returning if an empty file is given to it. The code block if (!@line) is never being executed. If I change that to be
if (@line)
than the code block is executed. I've read information on the perl split function over at http://perldoc.perl.org/functions/split.html and the discussion here 开发者_开发技巧about testing for an empty array but not sure what is going on here.
I am new to Perl so am probably missing something straightforward here.
- If the file is empty, the while loop body will not run at all.
Evaluating an array in scalar context returns the number of elements in the array.
split /,/
always returns a 1+ elements list if$_
is defined.
You might try some debugging:
...
chomp;
use Data::Dumper;
$Data::Dumper::Useqq = 1;
print Dumper( { "line is" => $_ } );
my @line = split/,/;
print Dumper( { "split into" => \@line } );
if (!@line) {
...
Below are a few tips to make your code more idiomatic:
- The special variable
$.
already holds the current line number, so you can likely get rid of$lctr
. - Are empty lines really errors, or can you ignore them?
- Pull apart the list returned from
split
and give the pieces names. - Let Perl do the opening with the "diamond operator":
The null filehandle
<>
is special: it can be used to emulate the behavior ofsed
andawk
. Input from<>
comes either from standard input, or from each file listed on the command line. Here's how it works: the first time<>
is evaluated, the@ARGV
array is checked, and if it is empty,$ARGV[0]
is set to"-"
, which when opened gives you standard input. The@ARGV
array is then processed as a list of filenames. The loopwhile (<>) { ... # code for each line }
is equivalent to the following Perl-like pseudo code:
unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } }
except that it isn't so cumbersome to say, and will actually work.
Say your input is in a file named input
and contains
Campbell's soup,0.50 Mac & Cheese,0.25
Then with
#! /usr/bin/perl
use warnings;
use strict;
die "Usage: $0 coupon-file\n" unless @ARGV == 1;
while (<>) {
chomp;
my($product,$discount) = split /,/;
next unless defined $product && defined $discount;
print "$product => $discount\n";
}
that we run as below on Unix:
$ ./coupons input Campbell's soup => 0.50 Mac & Cheese => 0.25
Empty file or empty line? Regardless, try this test instead of !@line
.
if (scalar(@line) == 0) {
...
}
The scalar
method returns the array's length in perl.
Some clarification:
if (@line) {
}
Is the same as:
if (scalar(@line)) {
}
In a scalar context, arrays (@line
) return the length of the array. So scalar(@line)
forces @line
to evaluate in a scalar context and returns the length of the array.
I'm not sure whether you're trying to detect if the line is empty (which your code is trying to) or whether the whole file is empty (which is what the error says).
If the line, please fix your error text and the logic should be like the other posters said (or you can put if ($line =~ /^\s*$/)
as your if).
If the file, you simply need to test if (!$lctr) {}
after the end of your loop - as noted in another answer, the loop will not be entered if there's no lines in the file.
精彩评论