2017-10-17 2 views
1

ソートされていないデータ

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 

は基本的に私は、ネット:: SFTPがリモートサイトをオフにディレクトリ一覧を取得するよファイル名に日付スタンプに基づいてperlでファイルのリストをソートする助けが必要ローカルファイルリストと比較することができます。私は、ファイル名の日付でリストをソートしたいのですが、無視しなければならない文字列に他の情報があるため、問題が発生しています。

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オブジェクトの組み込み比較が使用されます。次に、2番目のmapは元の文字列を引き出します。