2

perl スクリプトにかなり慣れていないので、助けが必要です。以下は私のクエリです:

以下のような内容のファイルがあります。

AA ABC 0 0 
line1
line2
...
AA XYZ 1 1
line..
line..
AA GHI 2 2
line..
line...

ここで、開始文字列/パターンを持つ行間のすべての行を取得し、"AA"それらをファイルに書き込みたいと思いますABC.txt, XYZ.txt, GHI.txt, それぞれ行を含む ,AA*ABC.txtは次のようになります

AA ABC 0 0
line1
line2...

そしてXYZ.txt次のように見えるはずです

AA XYZ 1 1
line..
line..

この質問が明確であることを願っています。これに関するヘルプは大歓迎です。

ありがとう、サンディ

4

4 に答える 4

3

ヘルプが必要なものを指定しなかったため、アルゴリズムを求めていると思います。

  1. 出力に使用するファイル ハンドルを宣言します。
  2. 入力ファイルの最後に達していない間に、
    1. 一行読む。
    2. ヘッダー行であれば、
      1. それを解析します。
      2. ファイル名を決定します。
      3. 出力ファイルを (再) 開きます。
    3. 行を出力ファイル ハンドルに出力します。

上記を投稿してから投稿された貧弱なソリューションの1つを使用したくない場合は、コードを次に示します。

my $fh;
while (<>) {
   if (my ($fn) = /^AA\s+(\S+)/) {
      $fn .= '.txt';
      open($fh, '>', $fn)
         or die("Can't create file \"$fn\": $!\n");
   }

   print $fh $_;
}

考えられる改善点。これらはすべて簡単に追加できます。

  • ヘッダーの重複を確認します。(if -e $fn片道です)
  • 最初のヘッダーの前のデータを確認します。(if !$fh片道です)
于 2012-11-21T01:08:25.910 に答える
0

これについてどう思いますか?

1:ファイルからコンテンツを取得し(おそらくFile :: Slurpのread_fileを使用して)、スカラーに保存します。

use File::Slurp qw(read_file write_file);
my $contents = read_file($filename);

2:次のような正規表現パターンマッチングを使用します。

my @file_rows = ($contents ~= /(AA\s[A-Z]{3}\s+\d+\s+\w*)/);

3:列2の値がファイル全体で常に一意である場合:

foreach my $file_row (@file_rows) {
    my @values = split(' ', $file_row, 3);
    write_file($values[1] . ".txt", $file_row);
}

3:それ以外の場合:行の値を分割します。2番目の列をキーとして使用して、それらをハッシュに格納します。ハッシュを使用して出力ファイルにデータを書き込みます。

my %hash;
foreach my $file_row (@file_rows) {
    my @values = split(' ', $file_row, 3);
    if (defined $hash{$value[1]}) {
        $hash{$values[1]} .= $file_row;
    } else {
        $hash{$values[1]} = $file_row;
    }
}

foreach my $key (keys %hash) {
    write_file($key .'txt', $hash{$key});
}
于 2012-11-21T01:25:34.037 に答える
0

これは、各レコードの先頭に一致するパターンを探すオプションです。見つかった場合は、データファイルの行をループして、同じパターンが再び見つかるまで、またはeofが見つかるまでレコードを作成します。その後、そのレコードがファイルに書き込まれます。ファイルに書き込む前にファイルがすでに存在するかどうかはチェックされないため、ABC.txtがすでに存在する場合は、次のように置き換えられます。

use strict;
use warnings;

my $dataFile    = 'data.txt';
my $nextLine    = '';
my $recordRegex = qr/^AA\s+(\S+)\s+\d+\s+\d+/;

open my $inFH, '<', $dataFile or die $!;

RECORD: while ( my $line = <$inFH> ) {
    my $record = $nextLine . $line;

    if ( $record =~ $recordRegex ) {
        my $fileName = $1 . '.txt';

        while ( $nextLine = <$inFH> ) {
            if ( $nextLine =~ $recordRegex or eof $inFH ) {
                $record .= $nextLine if eof $inFH;

                open my $outFH, '>', $fileName or die $!;
                print $outFH $record;
                close $outFH;

                next RECORD;
            }

            $record .= $nextLine;
        }
    }
}

close $inFH;

お役に立てれば!

編集:このコードは、問題があった元のコードを置き換えます。元のコードを確認していただき、ありがとうございます。

于 2012-11-21T01:44:33.480 に答える
0

一度に 1 つのファイルを開いたままにしておく必要があります... 行が に一致すると、ファイルXYZを開いてXYZ.txtその行を出力します。そのファイルを開いたままにし(ハンドルだとしましょうCURRENT_FILE)、新しいヘッダー行に一致するまで、連続する各行をそれに出力します。次に、現在のファイルを閉じて、別のファイルを開きます。

私の Perl は非常にさびているので、コンパイルできるコードを提供できるとは思いませんが、本質的にはこれに近いものです。

my $current_name = "";

foreach my $line (<INPUT>)
{
    my($name) = $line =~ /^AA (\w+)/;
    if( $name ne $current_name ) {
        close(CURRENT_FILE) if $current_name ne "";
        open(CURRENT_FILE, ">>", "$name.txt") || die "Argh\n";
        $current_name = $name;
    }
    next if $current_name eq "";
    print CURRENT_FILE $line;
}

close(CURRENT_FILE) if $current_name ne "";
于 2012-11-21T01:13:45.763 に答える