我希望通过基于给定密钥对每一行进行排序来修改文本文件,并将旧文件保存为备份。键是每行中包含的数字字符。
是否有一个简单的脚本来完成这项工作,最好是就地?
谢谢!
答案 0 :(得分:1)
存在具有O(n log n)复杂度的就地排序算法,例如Heapsort,但我不明白为什么你想要使用它而不是简单的东西,比如Unix {{1命令。除非你有严格的性能要求或庞大的数据集......但是,perl和python可能不是最好的工具。
答案 1 :(得分:1)
假设您的排序键是每行开头的数字运行,如下例所示。
5 Fine 2 Good 1 Every 4 Does 3 Boy
要对命令行中指定的一个或多个文件进行排序,您可以使用以下代码。
#! /usr/bin/env perl
use strict;
use warnings;
die "Usage: $0 file ..\n" unless @ARGV;
$^I = ".bak";
undef $/;
while (<>) {
print map $_->[0],
sort { $a->[1] <=> $b->[1] }
map { [ $_, /^(\d+)/ ? $1 : -1 ] }
/^(.*\n?)/mg;
}
@ARGV
包含命令行中的参数。运行没有参数的程序会产生标准错误的使用指南。
$^I
保留在为就地编辑创建备份时添加到文件名的扩展名,您也可以使用perlrun documentation中涵盖的Perl的-i
切换启用该扩展程序。
<强> -i [延伸] 强>
指定由<>
构造处理的文件将进行就地编辑。它通过重命名输入文件,按原始名称打开输出文件,并选择该输出文件作为
$/
是输入记录分隔符。将其设置为未定义的值意味着您希望后续调用readline operator来读取文件结尾。性能将因非常大的输入而受到影响。
在while
循环的每次迭代中,特殊变量$_
将整个保存当前文件的内容。为了对线条进行排序,我们首先将它们分开。
不要被循环内的print
吓倒。这是Schwartzian Transform,这是Perl中的常用技术,即使它首次亮相less-than-rave reviews。要了解发生了什么,请从头到尾阅读。
/m
正则表达式开关使^
在行的开头匹配,而不仅仅是在目标字符串的开头。print
输出到正在排序的当前文件。在更程序化的风格中,你将循环编写为
while (<>) {
my @lines = /^(.*\n?)/mg;
my @augmented = map { [ $_, /^(\d+)/ ? $1 : -1 ] } @lines;
my @sorted = sort { $a->[1] <=> $b->[1] } @augmented;
print map $_->[0], @sorted;
}
一旦你理解了Schwartzian变换正在发生的事情,所有临时工作看起来都是过分的混乱。
答案 2 :(得分:0)
没有一个简单的脚本可以做到这一点,因为你所建议的实际上是相当复杂和低效的。除非你的行在文件中的长度完全相同,否则几乎是不可能的(或者,非常愚蠢)。
如果你绝对不能在内存中做,并且想自己编写代码,那么你最好的方法可能是disk based merge sort。有关如何使用磁带机执行此操作的示例应该为您提供一些指导。