Perl разделить на пустой файл - PullRequest
2 голосов
/ 06 мая 2010

У меня есть в основном следующий Perl, с которым я работаю:

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;
 }
}

У меня проблемы с определением того, что возвращает функция split /, /, если ей дан пустой файл. Блок кода if (! @Line) никогда не выполняется. Если я изменю это на

if (@line)

чем выполняется блок кода. Я прочитал информацию о функции разделения Perl в http://perldoc.perl.org/functions/split.html и обсуждение здесь о тестировании на пустой массив, но не уверен, что здесь происходит.

Я новичок в Perl, поэтому, возможно, здесь что-то упущено.

Ответы [ 5 ]

5 голосов
/ 06 мая 2010
  1. Если файл пуст, тело цикла while не будет работать вообще.
  2. Оценка массива в скалярном контексте возвращает количество элементов в массиве.

    split /,/ всегда возвращает список из 1+ элементов, если определено $_.

2 голосов
/ 06 мая 2010

Вы можете попробовать отладку:

...
chomp;

use Data::Dumper;
$Data::Dumper::Useqq = 1;

print Dumper( { "line is" => $_ } );
my @line = split/,/;
print Dumper( { "split into" => \@line } );

if (!@line) {
...
1 голос
/ 07 мая 2010

Ниже приведены несколько советов, которые сделают ваш код более идиоматическим:

  • Специальная переменная $. уже содержит текущий номер строки, поэтому вы, вероятно, можете избавиться от $lctr.
  • Являются ли пустые строки действительно ошибками, или вы можете их игнорировать?
  • Раздвиньте список, возвращенный из split, и дайте названия кусочкам.
  • Пусть Perl сделает открытие с «оператором алмазов» :

Нулевой дескриптор файла <> является особенным: его можно использовать для эмуляции поведения sed и awk. Ввод из <> поступает либо из стандартного ввода, либо из каждого файла, указанного в командной строке. Вот как это работает: при первом вычислении <> проверяется массив @ARGV, а если он пуст, $ARGV[0] устанавливается на "-", что при открытии дает стандартный ввод. Затем массив @ARGV обрабатывается как список имен файлов. Петля

while (<>) {
... # code for each line
}

эквивалентен следующему Perl-подобному псевдокоду:

unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
  open(ARGV, $ARGV);
  while (<ARGV>) {
  ... # code for each line
  }
}

за исключением того, что это не так громоздко, и на самом деле будет работать.

Скажем, ваш ввод находится в файле с именем input и содержит

Campbell's soup,0.50
Mac & Cheese,0.25

Затем с

#! /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";
}

, который мы запускаем, как показано ниже в Unix:

$ ./coupons input
Campbell's soup => 0.50
Mac & Cheese => 0.25
0 голосов
/ 06 мая 2010

Я не уверен, пытаетесь ли вы определить, пуста ли строка (что пытается сделать ваш код) или пуст ли весь файл (именно об этом говорит ошибка).

Если в строке, пожалуйста, исправьте ваш текст ошибки, и логика должна быть такой же, как и в других постерах (или вы можете поставить if ($line =~ /^\s*$/) как ваше, если).

Если файл, вам просто нужно проверить if (!$lctr) {} после конца вашего цикла - как отмечено в другом ответе, цикл не будет введен, если в файле нет строк.

0 голосов
/ 06 мая 2010

Пустой файл или пустая строка? В любом случае, попробуйте этот тест вместо !@line.

if (scalar(@line) == 0) {
    ...
}

Метод scalar возвращает длину массива в perl.

Некоторые уточнения:

if (@line) {
}

То же, что и:

if (scalar(@line)) {
}

В скалярном контексте массивы (@line) возвращают длину массива. Таким образом, scalar(@line) заставляет @line вычислять в скалярном контексте и возвращает длину массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...