1

テストで質問があります:

ファイル内の行数と単語数を数えるプログラムの何が問題になっていますか?

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. ファイルに句読点がある場合、プログラムはそれらをカウントします。たとえば、

    abc cba
    , , ,dce
    

    5語になりますが、一方wcで同じ結果を出力するので、正しい動作と考えてよいでしょう。

  3. が大きなファイルの場合は、配列Fにダンプしないで、行を繰り返し処理する方がよい場合があります。lines

もっと些細なアイデアはありますか?

4

3 に答える 3

5

最初の行では、優先順位の問題があります。

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

と同じです

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

これは、が失敗したdie場合ではなく、ファイル名が false の場合に が実行されることを意味しopenます。あなたが言いたかった

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

また

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

$ARGV[0]また、何かを意味する文字が含まれている場合は、open の 3 つの引数形式を使用する必要がありますopen

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

別の注意として、分割と/\s/は、連続する空白文字の間に「単語」を取得することを意味します。「単語」をどのように定義するかに応じて、おそらく/\s+/、または amphetamachine が示唆したように を意味していました。/\W+/

それでも、行が空白で始まる場合に得られる空の「単語」の問題は残ります。分割し' 'てそれを抑制するか (特殊なケースです)、最初に先頭の空白を削除するか、a を挿入grep { length $_ }して空の「単語」を取り除くか、split単語を数えるための別の方法を放棄して使用することができます。

ファイル全体を一度に読み取るのではなく、1 行ずつ処理することも良い改善ですが、最初の 2 つの項目ほど重要ではありません。

于 2010-10-21T18:37:58.980 に答える
3
  • あなたの推測 #1 は正しくありopenません。失敗すると、プログラムは停止します。(操作の順序に関するcjmの回答を参照してください。)
  • レキシカル変数ではなく、グローバル ファイルハンドルを使用しています。
  • の 3 引数形式を使用していませんopen
  • 標準入力から読み取るだけで、入力に関する柔軟性が向上します。ユーザーはファイルを提供するか、入力を標準入力にパイプできます。
  • 最後に、単語を解析するために独自のコードを作成するつもりはありません。Lingua::EN::Splitterのように言うと、CPAN に手を伸ばします。
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;
于 2010-10-21T18:04:44.130 に答える
1

open F, $ARGV[0] || die $!ファイルが存在しない場合に効果的に終了する場合。

ここにはいくつかの改善点があります。

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

my @words = split /\W+/, $lines;
于 2010-10-21T18:02:36.287 に答える