2

我有两个文件

$猫文件 1
索引1注释1
A B C D
索引2注释2
efgh
索引3注释3
希克
索引4注释4
lmno
索引5注释5
pqrs
…
$猫文件2
索引1
索引3
索引5

我想要得到的是文件 1 中的行列表以及检索到的每一行之后的行,如下所示。

索引1注释1
A B C D
索引3注释3
希克
索引5注释5
pqrs

我目前的解决方案是使用 grep 及其“文件”标志 grep -A 1 --file="file2" file1 | awk '!/--/'

但我想知道是否有更优雅的解决方案。当文件很大时,当前的解决方案需要很长时间

4

2 回答 2

2
#!/usr/bin/env perl

use strict; use warnings;
use autodie;

my %to_index;

my ($annotations_file, $index_file) = @ARGV;

open my $index, '<', $index_file;

while (my $line = <$index>) {
    next unless $line =~ /\S/;
    chomp $line;
    $to_index{ $line } = undef;
}

close $index;

open my $annotations, '<', $annotations_file;

while (my $line = <$annotations>) {
    next unless $line =~ /\S/;
    my ($keyword) = ($line =~ /^(\S+)/);
    if (exists $to_index{ $keyword }) {
        print $line;
        print scalar <$annotations>;
    }
}

close $annotations;
于 2012-04-13T18:05:38.477 回答
2

我建议通读 file1 构建每个标签在文件中出现位置的索引。可以从file2中读取所需数据的标签,并查阅索引以查看从何处读取相应信息。

这个程序显示了原理。目前尚不清楚如何区分标签和测试的其余部分。我假设它们都以 开头Index,这可能是错误的,但如果您需要帮助以使其适应您的真实数据,请再次询问。

use strict;
use warnings;

@ARGV = qw/ file1.txt file2.txt / unless @ARGV;
my ($file1, $file2) = @ARGV;

my %index;

open my $f1, '<', $file1 or die qq(Unable to open "$file1": $!);
my $pos = tell $f1;
while (<$f1>) {
  $index{$1} = $pos if /^(Index\S+)/;
  $pos = tell $f1;
}

open my $f2, '<', $file2 or die qq(Unable to open "$file2": $!);
while (<$f2>) {
  next unless /^(Index\S+)/ and defined($pos = $index{$1});
  seek $f1, $pos, 0;
  print scalar <$f1>, scalar <$f1>;
}

输出

Index1 annotation1
abcd
Index3 annotation3
hijk
Index5 annotation5
pqrs
于 2012-04-13T18:56:44.520 回答