Что может быть не так с программой подсчета слов?

У меня есть вопрос в моем тесте:

Что не так с программой, которая подсчитывает количество строк и слов в файле?

open F, $ARGV[0] || die $!;
my @lines = <F>;
my @words = map {split /\s/} @lines;
printf "%8d %8d\n", scalar(@lines), scalar(@words);
close(F); 

Мои предположения таковы:

  1. Если файл не существует, программа нам об этом не сообщит.
  2. #P4# <блочная цитата>
    abc cba
    , , ,dce
    
    #P5#
  3. Если F — большой файл, может быть лучше перебирать строки, а не сбрасывать его в массив lines.

Есть ли у вас менее тривиальные идеи?


person alexanderkuk    schedule 21.10.2010    source источник


Ответы (3)


В первой строке у вас проблема с приоритетом:

open F, $ARGV[0] || die $!;

такой же как

open F, ($ARGV[0] || die $!);

что означает, что die выполняется, если имя файла ложно, а не в случае сбоя open. Ты хотел сказать

open(F, $ARGV[0]) || die $!;

or

open F, $ARGV[0] or die $!;

Кроме того, вы должны использовать 3-аргументную форму open, если $ARGV[0] содержит символы, которые что-то значат для open.

open F, '<', $ARGV[0] or die $!;

С другой стороны, разделение на /\s/ означает, что вы получаете «слово» между последовательными символами пробела. Вероятно, вы имели в виду /\s+/ или, как предложил амфетамин, /\W+/, в зависимости от того, как вы хотите определить «слово».

Это по-прежнему оставляет проблему пустого «слова», которое вы получаете, если строка начинается с пробела. Вы можете разделить на ' ', чтобы подавить это (это особый случай), или вы можете сначала обрезать начальные пробелы, или вставить grep { length $_ }, чтобы отсеять пустые «слова», или отказаться от split и использовать другой метод подсчета слов.

Построчная обработка вместо одновременного чтения всего файла также была бы хорошим улучшением, но это не так важно, как первые два пункта.

person cjm    schedule 21.10.2010
comment
Спасибо, я думаю, проблема приоритета - это ответ на этот вопрос. - person alexanderkuk; 21.10.2010

  • Ваша догадка №1 неверна: ваша программа умрет, если open выйдет из строя. (см. ответ cjm о порядке операций.)
  • вы используете глобальный дескриптор файла, а не лексическую переменную.
  • вы не используете трехаргументную форму open.
  • вы можете просто читать со стандартного ввода, что дает большую гибкость в отношении ввода - пользователь может предоставить файл или передать ввод на стандартный ввод.
  • наконец, я бы не стал писать собственный код для разбора слов; Я набирал CPAN, говорил что-то вроде Lingua::EN::Splitter .
use strict; use warnings;
use Lingua::EN::Splitter qw(words);
my ($wordcount, $lines);
while (<>)
{
    my $line = $_;
    $lines++;
    $wordcount += scalar(words $line);
}

printf "%8d %8d\n", $lines, $wordcount;
person Ether    schedule 21.10.2010
comment
Нет, он умрет, если имя файла будет ложным. Смотрите мой ответ. - person cjm; 21.10.2010

Когда вы open F, $ARGV[0] || die $!, это эффективно завершит работу, если файл не существует.

Здесь есть некоторые улучшения:

{local $/; $lines = <F>;} # read all lines at once

my @words = split /\W+/, $lines;
person amphetamachine    schedule 21.10.2010