1

ファイル内の文字の出現回数をカウントする perl スクリプトを作成しました。これまでのところ、これは私が持っているものです。

#!/usr/bin/perl -w

use warnings;
no warnings ('uninitialized', 'substr');

my $lines_ref;
my @lines;
my $count;

sub countModule()
{
my $file = "/test";
open my $fh, "<",$file or die "could not open $file: $!";
my @contents = $fh;
my @filtered = grep (/\// ,@contents);
return \@filtered;
}

@lines = countModule();
#@lines = $lines_ref;
$count = @lines;
print "###########\n $count \n###########\n";

私のテストファイルは次のようになります。

10.0.0.1/24
192.168.10.0/24
172.16.30.1/24

私は基本的に「/」のインスタンス数を数えようとしています

これは私が得る出力です:

###########
 1
###########

発生回数である 3 ではなく 1 を取得しています。まだperlを学んでいるので、どんな助けも感謝します..ありがとう!!

4

4 に答える 4

2

ここにあなたのコードに関するいくつかのポイントがあります

  • 常に use strictプログラムの先頭にいてno warnings、限られた範囲で特別な理由でのみ使用する必要があります。動作中の Perl プログラムが警告をグローバルに無効にする必要がある一般的な理由はありません。

  • 最初の使用ポイントの近くで変数を宣言します。ファイルの先頭ですべてを宣言するスタイルは不要であり、C の遺産です。

  • コードでプロトタイプを使用しないでください。これらは非常に特殊な目的で利用でき、大部分の Perl コードには使用しないでください。パラメータを指定して呼び出されることは決してなく、必要でも有用でもないとsub countModule() { ... }主張しています。countModule定義はsub countModule { ... }

  • 成功!レキシカル ファイル ハンドル、open の 3 パラメーター形式の使用、および$!型文字列の挿入

  • my @contents = $fh@contentsファイルハンドルだけを含む単一要素のリストに設定されます。ファイル全体を必要な配列に読み込むにはmy @contents = <$fh>

  • 別の区切り文字を使用すると、正規表現でスラッシュをエスケープすることを回避できます。mそのためには、次のように演算子を明示的に使用する必要がありますmy @filtered = grep m|/|, @contents)

  • 配列参照を返しますが、返された値を配列に割り当てるため、配列参照のみを含む単一要素リストに@lines = countModule()設定します。@linesでリストを返すかreturn @filtered、代入時に戻り値を逆参照する必要があります@lines = @{ countModule }

スラッシュ文字を含むファイル内の行数を出力するだけでよい場合は、次のように書くことができます

use strict;
use warnings;

my $count;

sub countModule {
  open my $fh, '<', '/test' or die "Could not open $file: $!";
  return [ grep m|/|, <$fh> ];
}

my $lines = countModule;
$count = @$lines;
print "###########\n $count \n###########\n";
于 2012-08-16T02:35:48.713 に答える
1

閉じますが、いくつかの問題があります。

use strict;
use warnings;

sub countModule
{
    my $file = "/test";
    open my $fh, "<",$file or die "could not open $file: $!";
    my @contents = <$fh>;  # The <> brackets are used to read from $fh.
    my @filtered = grep (/\// ,@contents);
    return @filtered;      # Remove the reference.
}

my @lines = countModule();
my $count = scalar @lines;  # 'scalar' is not required, but lends clarity.
print "###########\n $count \n###########\n";

私があなたのコードに加えた各変更には、何が行われたかを説明する #comment の注釈が付けられています。

リストコンテキストでは、サブルーチンはフィルタリングされた行を返します。スカラー コンテキストでは、フィルター処理された行数のカウントが返されます。

また、文字の出現を見つけることについても言及しました(スクリプト内のすべてが行指向であるにもかかわらず)。おそらく、カウンターサブは次のようになります。

sub file_tallies{
    my $file = '/test';
    open my $fh, '<', $file or die $!;
    my $count;
    my $lines;
    while( <$fh> ) {
        $lines++;
        $count += $_ =~ tr[\/][\/];
    }
    return ( $lines, $count );
}

my( $line_count, $slash_count ) = file_tallies();
于 2012-08-15T22:35:12.737 に答える
0

リストコンテキストでは、

return \@filtered;

は、1 つの要素 (名前付き配列への参照) を含むリストを返します@filtered。多分あなたはリスト自体を返したいと思っていました

return @filtered;
于 2012-08-15T22:31:06.483 に答える
-1

より簡単なコードを次に示します。

sub countMatches {
    my ($file, $c) = @_;   # Pass parameters
    local $/;
    undef $/; # Slurp input
    open my $fh, "<",$file or die "could not open $file: $!";
    my $s = <$fh>;  # The <> brackets are used to read from $fh.
    close $fh;
    my $ptn = quotemeta($c);  # So we can match strings like ".*" verbatim
    my @hits = $s =~ m/($ptn)/g;
    0 + @hits
}

print countMatches ("/test", '/') . "\n";

このコードは、Perl を非常に基本的なものから押し出していますが、過度ではありません。顕著な点:

  1. $/ の定義を解除すると、入力を 1 つの文字列に読み取ることができます。ファイル内の文字列の出現回数をカウントしていて、その文字列を含む行の出現回数をカウントしていない場合、通常、これは簡単に実行できます。

  2. m/(...)/g はすべてのヒットを検索しますが、「.」のような文字列をカウントする場合 それらのメタ文字を引用する必要があります。

  3. 結果を配列に格納して、リスト コンテキストで m// を評価します

  4. リストに 0 を追加すると、リスト内のアイテムの数が得られます。

于 2012-08-15T23:19:00.440 に答える