3

I have a file that looks like:

text text text text : 6 min
text text text text : 2 min
text text text text : 8 min
text text text text : 2 min

I need to sort this file to get that output :

text text text text : 2 min
text text text text : 2 min
text text text text : 6 min
text text text text : 8 min

I tried to do this but it doesn't work :

my @copy = ();
open (INFILE, $ARGV[0]);
while (<INFILE>) {
push (@copy, $_);
}
my @lines = sort grep /^: (\d+) min/ , @copy;
print @lines;

Is there any easy way to do this in perl ?

4

6 回答 6

8

使用以下方法更容易sort

$ sort -t: -k2 file
text text text text : 2 min
text text text text : 2 min
text text text text : 6 min
text text text text : 8 min
  • -t:表示“将列的分隔符设置为:”
  • -k2表示“在第 2 列过滤”,即在:.
于 2013-06-24T08:35:31.813 回答
5

我可能会推荐sort首先发布的解决方案,因为它看起来最简单。然而,这是一个 perl 版本。它基于Schwartzian 变换。这不是必需的,但对于任何较大的文件,它可能是有效的,而且看起来有点整洁。

use strict;
use warnings;

my @lines = <>;    # read the input file
@lines = map $_->[1],
         sort { $a->[0] <=> $b->[0] }
         map { my ($num) = /:\s*(\d+)/; [ $num, $_ ] } @lines;
print @lines;

基本思想是这样的:

  • 从提取数字的语句开始map,返回对包含该数字的二元素数组的引用,以及原始行[ $num, $_ ]
  • 根据第一个元素对结果列表进行排序。
  • 以另一个map语句结束,它将我们的数组转换回原始行。
于 2013-06-24T08:47:05.907 回答
1

你的正则表达式是错误的。你要:

/[^:]+: (\d+) min/

另外,你不能这样做吗?

@copy = <INFILE>;
于 2013-06-24T08:37:25.570 回答
1

If it has to be perl (fedorquis suggestion is very good), this nugget should do it:

my @file=<>;
foreach (sort {(split(' ',$a))[5] <=> (split(' ',$b))[5]} @file) {print;}

Give the filename as parameter.

于 2013-06-24T08:42:56.413 回答
0

您可以使用Schwartzian 变换根据数字对行进行排序,例如

use strict;
use Data::Dumper;

my @lines = ("Test:2 min","Test:8 min","Test:6 min");
print Dumper(\@lines);

@lines = map { $_->[0] }
    sort { $a->[1] <=> $b->[1] }
    map { [$_, /(\d+) min/] } @lines;

@lines = sort @lines;
print Dumper(\@lines);

输出:

$VAR1 = [
          'Test:2 min',
          'Test:8 min',
          'Test:6 min'
        ];
$VAR1 = [
          'Test:2 min',
          'Test:6 min',
          'Test:8 min'
        ];
于 2013-06-24T08:47:29.133 回答
0

my @lines = map { $_->[1] } sort { $a->[0] <=> $b->[0]} map { [ /:\s(\d+)/, $_ ] } @copy

这个怎么运作

从右边开始,第一个映射创建了一个数组数组。每个数组元素包含从每行提取的数字作为它的第一个元素,整行作为第二个元素

接下来,排序对刚刚使用所谓的 ufo 运算符设置的数组的第一个元素进行数字比较

最后,最后一张地图只提取了第二个元素,现在以正确的顺序

此方法称为“Schwartzian 变换”,位于 perldoc perlfaq4 部分“如何按(任何)对数组进行排序?”

于 2013-06-24T08:48:03.823 回答