ファイルを読み取った後、ファイル内の特定の文字を出力するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/969999

質問

Perlスクリプトを使用してファイルを読んでいます。このファイルはさまざまな文字を含む文字列で構成されており、文字「X」を含む文字列を識別することになっています。どうすればいいのか知りたいです (1) この文字列を出力します (「X」を含む) および (2) この文字列を別のファイルに書き込みます (3) ファイル全体の「X」文字の数を数えます. 。以下のスクリプトは、ファイル全体を再度出力します。助言がありますか?

#!/use/bin/perl
use strict;
use warnings;

open (FILE, "/home/user/Desktop/infile.phy") || die "cant open file\n";
my @body = <FILE>;
close (FILE);
my $count= 0;
my $string = '';
foreach $_(@body){
    if ($_ =~ m/[X]/){
        print "$_";
        $count++;
        print $count;
    }
    else {
        print ;
    }
}
exit;
役に立ちましたか?

解決

これはコードレビューなので、一つずつ見ていきましょう。

#!/use/bin/perl

そのシバン行はおそらくタイプミスです。おそらくそうあるべきです

#!/usr/bin/perl

または何でも which perl システムに戻ります。

use strict;
use warnings;

良い。

open (FILE, "/home/user/Desktop/infile.phy") || die "cant open file\n";

レキシカル ファイルハンドルを使用できる場合、パッケージ グローバル ファイルハンドルは必要ありません。3 引数形式の open 最近では好ましいです。また、エラー メッセージには、開けなかったファイルが示されているはずです。

my $filename = '/home/user/Desktop/infile.phy';
open my $input, '<', $filename
    or die "Cannot open '$filename' for reading: $!";

my @body = <FILE>;

ファイルを配列に読み込んでいます。この場合、それはまったく必要ありません。

my $count  = 0;
my $string = '';

可能な限り最小のスコープで変数を宣言し、(必要に応じて) 初期化します。

my $count;

変数 $string コード内の他の場所では使用されていません。

foreach $_(@body){

これはばかげています。 for ループ変数が指定されていない場合は $_ を使用します。代わりに字句ループ変数を指定すると、処理をわかりやすくすることができます。

for my $line ( @body ) {

ただし、ファイルを丸呑みする必要はないと思います。

        if ($_ =~ m/[X]/){

行に X が含まれている場合、一致は成功します。したがって、それは次と同等です /X/. 。ただし、これでは「X」を含む単語はわかりません。そのためには、単語が何であるかを判断し、単語レベルでマッチングを行う必要があります。

以上のことを念頭に置いて、次のスクリプトを検討してください。私が考える単語について単純化した仮定を立てました。これを基にしてすべての要件を満たすことができるはずです。

#!/usr/bin/perl

use strict;
use warnings;

my $filename = "$ENV{TEMP}/test.txt";
open my $input, '<', $filename
    or die "Cannot open '$filename' for reading: $!";

my $count;

while ( my $line = <$input> ) {
    my @words = grep { /X/ } split /\b/, $line;
    $count += @words;
    print join(', ', @words), "\n";
}

print "$count\n";

__END__

アップデート: 各行内で 1 つ以上の X 文字を含む単語を検索する必要がない場合、while ループは簡略化されます。

while ( <$input> ) { 
    $count += (my @matches = /(X)/g );
    print if @matches;
}

$_ を使用して。ただし、これはおそらく非効率的です (一致した X 文字をそれぞれ保存していることを考えると)。この場合、 tr 最もよく機能します:

my ($count, $n);
$n = tr/X// and $count += $n and print while <$input>;

他のヒント

印刷中です $_ if 節の両方の分岐にあります。else ブランチを削除します。

質問の「文字列」が「行」と等しいと仮定します。

use strict;
use warnings;

@ARGV=qw(/home/user/Desktop/infile.phy);

my $count = 0;
open my $outfile, '>', 'outfile' or die $!;
while (<>) {
  my $cnt = tr/X/X/;
  if ($cnt) {
    print;
    print $outfile $_;
  }
  $count += $cnt;
}

close $outfile or die $!;

print $count;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top