在Perl中对混合文本行(alphanum)进行排序

时间:2016-09-17 14:50:29

标签: perl sorting

我有txt文件,每个行结构都是这样的:

P[containerVrsn:U(0)recordVrsn:U(0)size:U(212)ownGid:G[mdp:U(1090171666)**seqNo:U(81920)**]logicalDbNo:U(1)classVrsn:U(1)timeStamp:U(0)dbRecord:T[classNo:U(1064620)size:U(184)updateVersion:U(3)checksum:U(748981000)

必须根据seqNo(min到max)对文件行进行排序。序列号实际上可以是从零开始的任何数字。知道如何以有效的方式完成它?

2 个答案:

答案 0 :(得分:2)

您可以使用Schwartzian Transform

这是一个完成工作的小脚本:

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

open my $fhi, '<', 'path/to/input/file' or die "Unable to open input file: $!";
my @lines = <$fhi>;
my @sorted = map { $_->[0] }
             sort { $a->[1] <=> $b->[1] }
             map { my ($x) = $_ =~ /SeqNo:U\((\d+)/i; [$_, $x]; }
             @lines;
open my $fho, '>', 'path/to/output/file' or die "Unable to open output file: $!";
print $fho $_ for @sorted;

答案 1 :(得分:2)

Toto's answer中建议的 Schwartzian变换可能是在这里对你的线进行排序的最快方法。但是你说你是一个Perl新手,而且我喜欢展示如何对这些行进行排序传统上

Perl有一个sort function,只需按字母顺序对列表进行排序。但是您可以提供自定义比较功能,让sort使用您的函数来比较元素。在其操作期间sort必须连续比较列表中的两个元素(=行),并决定哪一个更大或更小,或者它们是否相等。

如果您提供比较功能,sort会使用参数$a$b等两个元素来调用它。你不需要不能声明$a$b,它们是神奇的,就在那里。您的比较功能可能如下所示:

sub by_seqNo
{
    # extract the sequence number from $a and $b
    my ($seqA) = ($a =~ /seqNo:U\((\d+)/);
    my ($seqB) = ($b =~ /seqNo:U\((\d+)/);

    # numerically compare the sequence numbers (returns -1/0/+1)
    $seqA <=> $seqB;
}

前两行提取seqNo:U(后的数字,并将其存储为$seqA$seqB。第三行将这些序列号作为整数进行比较并返回结果。结合sort函数,可以得到:

my @sorted = sort by_seqNo @lines;

Schwartzian变换(ST)比这个解决方案更快的原因是因为ST执行(昂贵的)操作,从每行的线路中提取一次seqNo。 &#34;传统&#34;另一方面,方法为每次比较提取两次seqNo。