在 Perl 中比较三个文件
Posted
技术标签:
【中文标题】在 Perl 中比较三个文件【英文标题】:Comparing three files in Perl 【发布时间】:2019-12-20 08:00:45 【问题描述】:我有三个包含姓名和成绩的文本文件。我删除了成绩并仅使用名称创建了新文件。以下是文件的样子:
first.txt
爱丽丝 鲍勃 卡尔 井架 杰西卡 莎拉 扎克
second.txt
爱丽丝 鲍勃 井架 贾里德 杰西卡 莎拉 扎克
第三个.txt
鲍勃 贾里德 莎拉 板岩 特里 扎克
我想比较所有三个文件,如果一个文件中的名称不在另一个文件中,我想添加它。所以最后所有文件都将包含相同的名称。我知道你会在 perl 中添加行,所以必须创建一个新文件来执行此操作。
这是我的方法。我首先比较第一个和第二个,然后将第二个的差异添加到第一个中。然后比较第一和第二,从第一到第二添加差异。然后我将第二个文件(任何一个工作)与第三个文件进行比较,将第二个文件的差异打印到第三个文件中。然后我比较第二和第三,并将第三的差异打印到第一和第二。我也放入了比较语句以确保文件具有相同的条目。
带有成绩的文件命名为original1.txt
original2.txt
original3.txt
最后,我将获取包含新名称的文件,并将它们与具有等级的文件结合起来。如果文件中没有新名称的成绩,则它根本没有成绩条目。
有没有更清洁的方法来做到这一点?它看起来像一个巨大的混乱。
【问题讨论】:
你需要使用perl吗?这可能只是几行 shell - 鉴于文件已经排序,sort -um first.txt second.txt third.txt
将给出所有文件的所有名称。 (如果尚未排序,请删除 -m
)。然后join
与成绩文件合并...
use strict; use warnings;
使用适当的缩进。将重复的代码片段移动到sub
s。
整个脚本都在 perl 中,所以我尽量在纯 perl 中完成它,因为我的代码中有几个 sed 和 awk。不过,我也很欣赏你的建议。知道如何在 shell 中做事总是好的。尤其是交叉检查。 @肖恩
@罗伯特哇。我不敢相信我没想过把它放进一个潜艇。那肯定会让它更干净。
【参考方案1】:
除非这是针对一个类或某些使用 perl 是硬性要求的东西,否则更简洁的方法是根本不使用 perl,而是使用标准的 shell 实用程序。
假设您的 originalN.txt
文件如下所示:
Alice A
Bob B
Carl C
Derrick D
Jessica A
Sarah B
Zach C
用标签分隔列
你可以这样做:
sort -um <(cut -f1 original1.txt) \
<(cut -f1 original2.txt) \
<(cut -f1 original3.txt) > allnames.txt
要从所有三个文件中获取包含所有名称的文件(如果它们尚未按名称排序,请改用sort -u ...
)。对于 <(command)
重定向语法,这确实需要 bash、zsh 或 ksh93。
然后您可以将这些名称与每个单独的文件合并,并带有一个左外部join
:
$ join -t$'\t' -a1 allnames.txt original1.txt
Alice A
Bob B
Carl C
Derrick D
Jared
Jessica A
Sarah B
Slate
Terry
Zach C
等等。
如果使用 perl,则不需要所有这些临时文件。只需将所有原始文件的名称粘贴在哈希中即可:
#!/usr/bin/env perl
use warnings;
use strict;
use autodie;
use feature qw/say/;
# Read all names from the files given on the command line.
my %names;
for my $file (@ARGV)
open my $infile, "<", $file;
while (<$infile>)
my $n = ( split /\t/ )[0];
$names$n = 1;
# And for each file, merge with all the names
for my $file (@ARGV)
say "****** $file *******";
open my $infile, "<", $file;
my %grades = map $_ => undef keys %names;
while (<$infile>)
chomp;
my ( $name, $grade ) = split /\t/;
$grades$name = $grade;
for my $name ( sort keys %grades )
if ( defined $grades$name )
say "$name\t$grades$name";
else
say $name;
将结果写入文件而不是标准输出留给读者作为练习。
【讨论】:
以上是关于在 Perl 中比较三个文件的主要内容,如果未能解决你的问题,请参考以下文章
perl 的 XML::SemanticDiff 可以硬塞到两个 XML 文件的顺序不可知比较中吗?