2009-05-05 80 views
2

定期接收我们无法控制的外部来源的CSV文件。这些文件是当前记录的完整集合;但是,自上次以来删除的任何记录都不存在。我们想比较这两个文件并创建一个单独的已删除记录文件,以便我们可以对它们进行一些额外的处理。在另一个领域的应用程序中,我们有一个商业分类包(CoSort),它可以实现这一功能;然而,我们在这里没有访问权限。尽管如此,这些数量并不是那么大,看起来这是标准或免费工具可能很容易处理的事情。理想情况下,这将采用Windows批处理文件的形式,但Perl或awk解决方案也可以。例如输入文件:在Windows中,如何比较两个文件并仅返回第一个文件中原来存在的第二个文件中缺少的记录?

上一个文件:

X_KEY,X_NAME,X_ATTRIBUTE 
123,Name 123,ATT X 
111,Name 111,ATT X 
777,Name 777,ATT Y 

传入的文件:

X_KEY,X_NAME,X_ATTRIBUTE 
777,Name 777,ATT Y 
123,Name 123,ATT CHANGED 

生成的文件应至少包括:

111,Name 111 

但是,如果被删除的属性记录也通过,这很好。

到目前为止,我有一个使用免费软件CMSort两个文件减去头记录进行排序的批处理文件,以使其更容易为某些类型的DIFF过程:

REM Sort Previous File, Skip Header 

C:\Software\CMSort\cmsort.exe /H=1 x_previous.txt x_previous_sorted.txt 

REM Sort Incoming File, Skip Header 

G:\Software\CMSort\cmsort.exe /H=1 x_incoming.txt x_incoming_sorted.txt 

但“比较,只有展示从第一个文件丢失的记录'位是逃避我。复杂性的一部分是许多属性可以在剩下的记录中改变,所以它不是纯粹的差异。然而,它感觉就像是一个专门的diff命令 - 它只限于检查关键字段,而不是整个记录。不过,我似乎无法得到正确的语法。想法?记录数不应超过5万条记录。

注意:如果这是SQL并且数据位于表中,我们可以使用EXCEPT operator,但在这种情况下将数据移到数据库不是一个选项。

+2

既然你提到差异,这是值得注意的是,diffutils的是可用于Windows : http://gnuwin32.sourc eforge.net/packages/diffutils.htm – si28719e 2009-05-05 23:54:33

回答

2

,如果我是这样做在Perl中我只用一对夫妇的哈希,


#!/usr/bin/perl -w                           
use strict; 
use warnings; 

my %orig; my %new; my %changed; 

open(F1,"<$ARGV[0]")||die"Couldn't open $ARGV[0]: $!\n"; 
while(<F1>){ 
    chomp; 
    @_ = split(/,/); 
    $orig{$_[0]} = $_; 
} 
close(F1); 

open(F2,"<$ARGV[1]")||die"Couldn't open $ARGV[1]: $!\n"; 
while(<F2>){ 
    chomp; 
    @_ = split(/,/); 
    if($orig{$_[0]}){ 
     if($orig{$_[0]} ne $_){ 
      $changed{$_[0]} = $orig{$_[0]}."||".$_; 
     } 
     delete $orig{$_[0]}; 
    }else{ 
     $new{$_[0]} = $_; 
    } 
} 
close(F2); 

print "Deleted:\n"; 
print map{$orig{$_}."\n"} sort {$b<=>$a} keys %orig; 
print "Added:\n"; 
print map{$new{$_}."\n"} sort {$b<=>$a} keys %new; 
print "Changed:\n"; 
print map{$changed{$_}."\n"} sort {$b<=>$a} keys %changed; 

假设你的文字的例子是在文件f1.txt和f2.txt,


kettle$ ./compare.pl f1.txt f2.txt 

Deleted: 
111,Name 111,ATT X 
Added: 
Changed: 
123,Name 123,ATT X||123,Name 123,ATT CHANGED 

0

编写一个经过第一个文件的小控制台应用程序并解析出键并检查第二个文件中与键匹配的行并创建第三个文件并不困难。我想我说这似乎是一个很好的情况下推出自己的。 :)顺便说一句,这是一个O(mn)操作,其中m,n是文件1和文件2的大小,所以它可能不会很快。

1
#!/usr/bin/perl 

use strict; 
use warnings; 

@ARGV == 2 or die "mycompare oldfile newfile\n"; 

my ($oldfile, $newfile) = @ARGV; 

my %newrecords; 

open my $new, '<', $newfile 
    or die "Cannot open '$newfile':$!"; 

scalar <$new>; # skip header 

while (my $line = <$new>) { 
    next unless $line =~ /\S/; 
    my ($record) = split /,/, $line; 
    $newrecords{ $record } = 1; 
} 

close $new; 

open my $old, '<', $oldfile 
    or die "Cannot open '$oldfile': $!"; 

scalar <$old>; # skip header 

while (my $line = <$old>) { 
    next unless $line =~ /\S/; 
    my ($record) = split /,/, $line; 
    print $line unless exists $newrecords{ $record }; 
} 

close $new; 

__END__ 

C:Temp> mycompare old.csv new.csv 
111,Name 111,ATT X 
0

我会使用diff,如果它不能直接使用,请通过cygwin使用它。

0

我以前在很长一段时间的工作依稀相似的系统上一次(令人不安的接近20年前,其实)。数据存储在数据库中,并且传入的数据必须与前一周的数据进行比较。数据中有74列数据,其中一些采用'prev code,prev date'对(几个周期)的形式。所以,一个合法的组更改是为:

Old: 
name1: value1  date1: 2000-01-01 
name2: value2  date2: 1995-05-31 
name3: value3  date3: 1990-10-13 

New: 
name1: New Name  date1: 2009-03-31 
name2: Other Name date2: 2005-04-12 
name3: value1  date3: 2000-01-01 

在这种情况下,究竟是什么“名1,DATE1”已经成为“NAME3,DATE3”;在过去某个时间似乎出现了中间名称变更,并且最近名称发生了变化。关于名称变化的情报可能会延迟。弄清楚之前发生的事情以及全新的事情是非常艰难的。事实上,整个过程很棘手。

我实际上开发了一个双语自我再生程序来管理这些东西。源代码的顶部利用了主要语言(Informix 4GL)中的注释符号,它使用了shell风格的#... eol注释和{...}注释(后者能够遍布多行。当然,这也是一个用于I/O重定向的shell构造,所以我有了一个shell脚本,它将生成嵌入在{...}注释中的I4GL代码,并且该代码是从定义70 +柱和如何每一个需要进行处理。这节省了很多时间打字。 ^ h