如何比较两个文件之间的值?

时间:2019-01-25 11:25:47

标签: perl sorting awk sed sdiff

我有两个文件,两列之间用空格隔开

cat file1.txt
281475225437349 33,32,21,17,20,22,18,30,19,16,23,31
281475550885480 35,32,33,21,39,40,57,36,41,17,20,38,34,37,16,99

cat file2.txt
281475550885480 16,17,20,21,32,33,34,35,36,37,38,39,40,41
281475225437349 16,17,18,19,20,21,22,23,24,25,30,31,32,33

我想比较file1 column2和file2 column2中的值,以获取column1中相同的值。 并仅打印在file1 column2中存在但在file2 column2中不存在的那些值,反之亦然,以及在column1中分别显示的那些值

所需的o / p

它不应该为281475225437349打印任何内容,因为281475225437349的file2列2中的file1列2中的所有值都存在

它应该只打印281475550885480的值,该值出现在file1 column2中,而没有出现在file2 column2中。像281475550885480的值57和99

o / p文件如下:

cat output.txt
281475550885480 57,99

我已经尝试过使用sdiff对文件进行排序和比较,但它会带来差异和耗时

sdiff file1.txt file2.txt

6 个答案:

答案 0 :(得分:3)

Perl解决方案:从第二个文件创建哈希散列。键是较大的数字,内键是逗号分隔列表中较小的数字。然后遍历第一个文件,并检查在记住的结构中未提及哪些数字。

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

open my $f1, '<', 'file1' or die $!;
open my $f2, '<', 'file2' or die $!;

my %seen;
while (<$f2>) {
    my ($key, $value_string) = split ' ';
    my @values = split /,/, $value_string;  #/
    undef @{ $seen{$key} }{@values};
}
while (<$f1>) {
    my ($key, $value_string) = split ' ';
    my @values = split /,/, $value_string;
    my %surplus;
    undef @surplus{@values};
    delete @surplus{ keys %{ $seen{$key} } };
    say $key, ' ', join ',', keys %surplus
        if keys %surplus;
}

顺便说一句,当您切换文件时,输出将为

281475225437349 24,25

因为文件1中没有24和25。

答案 1 :(得分:1)

这可能对您有用(GNU sed):

sed -r 's#^(\S+)\s(\S+)$#/^\1 /s/$/,\\n\2,/#' file2 |
sed -rnf - -e ':a;s/(\b[0-9]+,)(.*\n.*)\1/\2/;ta;s/(.*),\n.*/\1/p' file1

解决方案可以分为两部分。

第一个file2变成sed脚本,该脚本将每个键的值附加到file1中的相同键。添加了附加的,以使匹配更容易,并且将指示file1中的行是否有要打印的值。

从file2生成的脚本通过管道传递到第二个sed调用中,另外一个下标使用替换和循环从file1中删除匹配的值。

在匹配失败的情况下,并且由于第二次sed调用使用-n开关使显示明确,最终匹配将删除在换行符之后引入的,和不匹配的值并打印所需的结果。

答案 2 :(得分:0)

您必须在代码中使用两个循环。还要在

之后拆分','字符并设置两个数组
foreach(var itemOne as arrayOne){
boolean isExist=false;
foreach(var itemTwo as arrayTwo)
if(itemOne==itemTwo) isExist=true;

if(isExist) console.log(itemOne+" is exist");
}

答案 3 :(得分:0)

这对于awk很简单:

awk '(NR==FNR) { a[$1]=","$2","; next }
     { delete b }                   # clear array for new run
     { split($2,f,",") }            # split string of file1 in array f
     { for(i in f) if (! match(a[$1],"," f[i] ",")) b[f[i]]  }                                                                                                                                                                             
     { c=$1" "; for(i in b) {printf c i; c="," }; if (c==",") printf "\n" }' file2 file1

返回:

281475550885480 57,99

这个想法是用额外的两个<逗号>存储第二列的字符串,以确保每个数字都在逗号之间。然后搜索逗号分隔的子字符串。

如果必须进行实数检查,并且可能需要将数字“ 5”与“ 005”进行比较,并且它们应该相等,那么您应该执行以下操作:

awk '(NR==FNR) { a[$1]=$2; next }
     { delete b }                       # clear array
     { # split strings in number elements
       split($2,f,",");    for(i in f) f1[f[i]+0];
       split(a[$1],f,","); for(i in f) f2[f[i]+0]
     }
     { for(i in f1) if (! (i in f2)) b[i] }
     { c=$1" "; for(i in b) {printf c i; c="," }; if (c==",") printf "\n" }' file2 file1

答案 4 :(得分:0)

$ cat tst.awk
BEGIN { FS="[ ,]" }
NR==FNR {
    for (i=2; i<=NF; i++) {
        file2[$1,$i]
    }
    next
}
{
    diff = ""
    for (i=2; i<=NF; i++) {
        if ( !(($1,$i) in file2) ) {
            diff = (diff == "" ? "" : diff ",") $i
        }
    }
    if (diff != "") {
        print $1, diff
    }
}

$ awk -f tst.awk file2 file1
281475550885480 57,99

答案 5 :(得分:0)

另一个awk

$ awk -v c=, 'NR==FNR {a[$1]=$2; next}
                      {for(i=2;i<=NF;i++) 
                         {if(c a[$1] c !~ c $i c) p=(p==""?$1" ":p c) $i} 
                          if(p) print p; p=""}' file2 FS=' |,' file1

281475550885480 57,99