如何筛选文件列表以删除已知重复项

时间:2017-08-11 09:04:42

标签: perl duplicates

我有以下文件列表: INV_1400524_20170412_052945.pdf INV_1400524_20170412_063522.pdf INV_1400524_20170412_090338.pdf INV_1400524_20170412_092911.pdf INV_1400971_20170502_095250.pdf INV_1401580_20170703_100410.pdf INV_1401880_20170804_112917.pdf RIN_1300355_20170503_014347.pdf RIN_1300552_20170518_111143.pdf RIN_1300552_20170518_122055.pdf RIN_1300688_20170627_040340.pdf RIN_1300834_20170727_113641.pdf RIN_1300834_20170727_154404.pdf

格式为:

<Document Type>_<Document Number>_<Date>_<Time>.pdf

如您所见,由于某种原因,多次输出相同的文档编号。我想忽略重复项并将列表过滤到唯一的文档编号和最新日期。这些文档还有一个修改过的文件时间戳,如果有帮助,它会与文件名中的日期和时间紧密匹配。

使用perl(我一直在使用File :: Find :: Rule)我想将列表缩减为: INV_1400524_20170412_092911.pdf INV_1400971_20170502_095250.pdf INV_1401580_20170703_100410.pdf INV_1401880_20170804_112917.pdf RIN_1300355_20170503_014347.pdf RIN_1300552_20170518_122055.pdf RIN_1300688_20170627_040340.pdf RIN_1300834_20170727_154404.pdf

我已经开始了

my @pdf_files = File::Find::Rule->new
  ->in($root_dir)
   ->name( '*.pdf' )
   ->mtime (">$days_ago");

但是看看这个答案: How can I find the newest .pl file in a directory and all its subdirectories using Perl?

我认为可能有一种使用方法:

my $rule = File::Find::Rule->new;
$rule->or( $rule->new->name('INV_*.pdf')->....
$rule->or( $rule->new->name('RIN_*.pdf')->....
my @files = $rule->in($root_dir);

将它们分组并过滤掉。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

使用grep

是一个很好的习语
my %seen; 
my @files = grep { not $seen{$_}++ } @files;

因为你是增量后测试,所以第一次测试是真的,所有其他测试都是假的。你也可以使用正则表达式来匹配例如子串。文件ID:

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;

chomp(
   my @files = <DATA>
);

my %seen;
@files = grep { m/(\d+)/ and not $seen{$1}++ } @files;

print Dumper \@files;

__DATA__
INV_1400524_20170412_052945.pdf
INV_1400524_20170412_063522.pdf
INV_1400524_20170412_090338.pdf
INV_1400524_20170412_092911.pdf
INV_1400971_20170502_095250.pdf
INV_1401580_20170703_100410.pdf
INV_1401880_20170804_112917.pdf
RIN_1300355_20170503_014347.pdf
RIN_1300552_20170518_111143.pdf
RIN_1300552_20170518_122055.pdf
RIN_1300688_20170627_040340.pdf
RIN_1300834_20170727_113641.pdf
RIN_1300834_20170727_154404.pdf

输出:

$VAR1 = [
          'INV_1400524_20170412_052945.pdf',
          'INV_1400971_20170502_095250.pdf',
          'INV_1401580_20170703_100410.pdf',
          'INV_1401880_20170804_112917.pdf',
          'RIN_1300355_20170503_014347.pdf',
          'RIN_1300552_20170518_111143.pdf',
          'RIN_1300688_20170627_040340.pdf',
          'RIN_1300834_20170727_113641.pdf'
        ];

如果您的标准更加合理,那么您可能需要应用排序以确保“首先”。过滤到顶部。

有两种方法 - 你可以sort使用文件名 - 而且因为你有一个ISO日期,看起来它会起作用:

@files = grep { m/(\d+)/ and not $seen{$1}++ } sort @files;

或者你可以根据stat系统调用进行某种排序(为此你需要完整的文件路径,所以要注意!)

@files = grep { m/(\d+)/ and not $seen{$1}++} sort { -M $a <=> -M $b } @files;

-M是用于检查文件年龄(以天为单位)的perl filetest。

但您可以使用stat代替。