我有一个看起来像的文件:
text text text text : 6 min
text text text text : 2 min
text text text text : 8 min
text text text text : 2 min
我需要对此文件进行排序以获得该输出:
text text text text : 2 min
text text text text : 2 min
text text text text : 6 min
text text text text : 8 min
我试图这样做,但它不起作用:
my @copy = ();
open (INFILE, $ARGV[0]);
while (<INFILE>) {
push (@copy, $_);
}
my @lines = sort grep /^: (\d+) min/ , @copy;
print @lines;
有没有简单的方法在perl中执行此操作?
答案 0 :(得分: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
表示“在第二列上过滤”,即在:
之后。答案 1 :(得分:4)
我可能会建议首先发布sort
解决方案,因为它似乎最简单。这是一个perl版本。它基于Schwartzian transform。这不是必需的,但对于任何较大的文件,它可能是有效的,而且看起来有点整洁。
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
语句结束,将我们的数组转换回原始行。答案 2 :(得分:1)
你的正则表达式错了。你想要:
/[^:]+: (\d+) min/
另外,你不能这样做吗?
@copy = <INFILE>;
答案 3 :(得分:1)
如果必须是perl(fedorquis建议非常好),这个金块应该这样做:
my @file=<>;
foreach (sort {(split(' ',$a))[5] <=> (split(' ',$b))[5]} @file) {print;}
将文件名作为参数。
答案 4 :(得分: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'
];
答案 5 :(得分:0)
my @lines = map { $_->[1] } sort { $a->[0] <=> $b->[0]} map { [ /:\s(\d+)/, $_ ] } @copy
工作原理
从右边开始,第一个地图生成一个数组数组。每个数组元素包含从每一行中提取的数字作为第一个元素,整行作为第二个元素
接下来,排序适用于刚刚使用所谓的ufo运算符设置的数组的第一个元素进行数值比较
最后,最后一张地图仅提取第二个元素,现在顺序正确
此方法称为“Schwartzian变换”,位于perldoc perlfaq4部分“如何按(任何)排序数组?”