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. 将该行打印到输出文件句柄。

以免您想使用自我发布上述内容以来发布的不良解决方案之一,这是代码:

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

您只需要一次打开一个文件...当一行匹配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 回答
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:否则:拆分行值。使用第二列作为键将它们存储到散列中。使用哈希将数据写入输出文件。

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;

希望这可以帮助!

编辑:此代码替换有问题的原始代码。感谢amon审查原始代码。

于 2012-11-21T01:44:33.480 回答