2017-10-17 54 views
1

未排序的數據需要幫助的基礎上的日期戳在文件名排序perl的文件列表

5CM00225_10_16_2017_10_54_42.xml 
5CM10538_10_16_2017_11_04_18.xml 
1ZM06004_10_16_2017_11_04_14.xml 
5XM10010_10_17_2017_08_00_47.xml 
5ZM05391_10_15_2017_08_51_07.xml 
5ZM05388_10_17_2017_08_01_06.xml 
5ZM00058_10_17_2017_08_00_49.xml 
NMC00166_10_15_2017_08_51_06.xml 
5CM10538_10_15_2017_08_51_06.xml 

預期結果

NMC00166_10_15_2017_08_51_06.xml 
5CM10538_10_15_2017_08_51_06.xml 
5ZM05391_10_15_2017_08_51_07.xml 
5CM00225_10_16_2017_10_54_42.xml 
1ZM06004_10_16_2017_11_04_14.xml 
5CM10538_10_16_2017_11_04_18.xml 
5XM10010_10_17_2017_08_00_47.xml 
5ZM00058_10_17_2017_08_00_49.xml 
5ZM05388_10_17_2017_08_01_06.xml 

基本上我的Net :: SFTP得到一個目錄列表關閉遠程站點並與本地文件列表進行比較。我想按文件名按日期對列表進行排序,但由於字符串中還有其他信息需要忽略,因此遇到問題。

my $sftp = Net::SFTP->new($host, %args); 

my @list = $sftp->ls($path); 

open(my $fh, '>', $file); # open a log file to save remote directory listing 

    my @sorted = map { $_->[0] } 
     sort { $a->[1] <=> $b->[1] } 
     map { [$_, $_=~/(\d{2})_(\d{2})_(\d{4})_(\d{2})_(\d{2})_(\d{2})/] } # unsuccessful sorting attempt 
     @list; 

    foreach my $item (@sorted) { 
     $i = ${item}->{filename};        
     print $fh "$1\n"; # prints each record to the open log file 
    } 
close $fh; 

我已經做了在同一時間之前和大量的正則表達式,但從未排序,我很清楚地笨拙起來,因爲它沒有任何的排序,並沒有拋出任何錯誤。

我想過從每個字符串中提取DD_MM_YYYY_hh_mm_ss並試圖用它作爲參考,但沒有提供任何有用的進展,所以我刮掉了這個想法。

回答

3

這產生你想要的輸出。它將下劃線或句點中的每一行分割成一個列表,然後只按照你想要的順序保留你想要的「列」。它保持年份,接着是月份,日期等等。然後它將列表元素連接到一個新的日期字符串中,然後根據日期對行進行排序。

use warnings; 
use strict; 

my @list; 
while (<DATA>) { 
    chomp; 
    push @list, $_; 
} 

my @sorted = map { $_->[0] } 
    sort { $a->[1] <=> $b->[1] } 
    map { [$_, join '', (split /[_.]/)[3,1,2,4,5,6] ] } 
@list; 

__DATA__ 
5CM00225_10_16_2017_10_54_42.xml 
5CM10538_10_16_2017_11_04_18.xml 
1ZM06004_10_16_2017_11_04_14.xml 
5XM10010_10_17_2017_08_00_47.xml 
5ZM05391_10_15_2017_08_51_07.xml 
5ZM05388_10_17_2017_08_01_06.xml 
5ZM00058_10_17_2017_08_00_49.xml 
NMC00166_10_15_2017_08_51_06.xml 
5CM10538_10_15_2017_08_51_06.xml 

我相信,因爲它返回他們出現在該行,即月,日的順序列表你的代碼沒有等

+1

比我的解決方案要好得多! – Andrey

+1

謝謝!簡單的解決方案,完全按要求工作。看到你做了什麼不同,突出了爲什麼我沒有意義,感謝你的幫助。 – frozenthorn

1

也許不是最漂亮的解決方案,但它的工作原理:

use strict; 
use warnings; 
use Data::Dumper; 

my @list = (
    '5CM00225_10_16_2017_10_54_42.xml', 
    '5CM10538_10_16_2017_11_04_18.xml', 
    '1ZM06004_10_16_2017_11_04_14.xml', 
    '5XM10010_10_17_2017_08_00_47.xml', 
    '5ZM05391_10_15_2017_08_51_07.xml', 
    '5ZM05388_10_17_2017_08_01_06.xml', 
    '5ZM00058_10_17_2017_08_00_49.xml', 
    'NMC00166_10_15_2017_08_51_06.xml', 
    '5CM10538_10_15_2017_08_51_06.xml' 
); 

my @sorted = sort { 
    my ($mm1,$dd1,$yy1,$hh1,$min1,$ss1) = ($a =~ /_(\d{2})_(\d{2})_(\d{4})_(\d{2})_(\d{2})_(\d{2})\.xml$/); 
    my ($mm2,$dd2,$yy2,$hh2,$min2,$ss2) = ($b =~ /_(\d{2})_(\d{2})_(\d{4})_(\d{2})_(\d{2})_(\d{2})\.xml$/); 
    my $x = $yy1.$mm1.$dd1.$hh1.$min1.$ss1; 
    my $y = $yy2.$mm2.$dd2.$hh2.$min2.$ss2; 
    $x <=> $y; 
} @list; 

print Dumper(\@sorted); 
1

解析和比較日期,這裏使用日期時間模塊Time::Piece也是有意義的。

甲幼稚版本(參見下文的更有效的一個)

use warnings; 
use strict; 
use feature 'say'; 

use Time::Piece; 

my @orig = ( 
    '5CM00225_10_16_2017_10_54_42.xml', 
    '5CM10538_10_16_2017_11_04_18.xml', 
    '1ZM06004_10_16_2017_11_04_14.xml', 
    '5XM10010_10_17_2017_08_00_47.xml', 
    '5ZM05391_10_15_2017_08_51_07.xml', 
    '5ZM05388_10_17_2017_08_01_06.xml', 
    '5ZM00058_10_17_2017_08_00_49.xml', 
    'NMC00166_10_15_2017_08_51_06.xml', 
    '5CM10538_10_15_2017_08_51_06.xml', 
); 

my $dt = Time::Piece->new; 

my @sorted = sort { 
    my $a_dt = $dt->strptime($a =~ /_(.*)\./, '%m_%d_%Y_%H_%M_%S'); 
    my $b_dt = $dt->strptime($b =~ /_(.*)\./, '%m_%d_%Y_%H_%M_%S'); 
    $a_dt <=> $b_dt 
} @orig; 

say for @sorted; 

這將運行對每個比較的正則表達式和strptime

相反,預先計算所有這些

my @sorted = 
    map { $_->[1] } 
    sort { $a->[0] <=> $b->[0] } 
    map { [ $dt->strptime(/_(.*)\./, '%m_%d_%Y_%H_%M_%S'), $_ ] } 
    @orig; 

這提取字符串的日期 - 時間部分,並建立從它的日期時間對象與strptime,與原來的字符串將其放置在一個數組引用在一起。它使用map來完成整個輸入。

然後,該列表被傳遞給sort,該列表按其第一個元素進行排序,其中使用了Time::Piece對象的內置比較。然後第二個map拉出原來的字符串,爲我們的結果。