Я хочу изменить текстовый файл, отсортировав каждую строку на основе заданного ключа и сохраните старый файл в качестве резервной копии. Ключ - это числовой символ, содержащийся в каждой строке.
Есть ли простой script, чтобы сделать это, желательно на месте?
Спасибо!
Скажите, что ваш ключ сортировки - это пробег цифр в начале каждой строки, как в следующем примере.
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
содержит расширение, добавленное к именам файлов при создании резервных копий для редактирования на месте, которые вы также можете включить с помощью Perl -i
переключатель, описанный в документации perlrun.
-i [расширение]
указывает, что файлы, обработанные конструкцией<>
, редактируются на месте. Он делает это, переименовывая входной файл, открывая выходной файл исходным именем и выбирая этот выходной файл как значение по умолчанию для операторов
$/
- это разделитель входных данных. Установка его в значение undefined означает, что вы хотите выполнить последующие вызовы оператора readline для чтения конца файла. Производительность будет очень большой.
На каждой итерации цикла while
специальная переменная $_
будет содержать содержимое текущего файла в целом. Чтобы отсортировать строки, мы сначала разделим их.
Не запугайте print
внутри цикла. Это Schwartzian Transform, обычная техника в Perl, хотя она дебютировала less -это-восторженные отзывы. Чтобы понять, что происходит, прочитайте его от конца до начала.
/m
regex делает совпадение ^
в начале строки не только в начале целевой строки.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;
}
Как только вы поймете, что происходит с трансформацией Шварца, все временные лица кажутся чрезмерными беспорядками.
Существуют алгоритмы сортировки на месте с сложностью O (n log n), такие как Heapsort, но я не понимаю, почему вы хотели бы использовать это, а не что-то простое, например, команду Unix sort
. Если у вас нет жестких требований к производительности или огромных наборов данных... но тогда, perl и python, вероятно, не лучшие инструменты для работы.
Для этого не существует простого script, потому что то, что вы предлагаете, на самом деле довольно сложно и неэффективно. Если ваши строки не имеют одинаковой длины в файле, это почти невозможно (или, что невероятно глупо).
Если вы абсолютно не можете сделать это в памяти и хотите сами написать код, ваш лучший подход, вероятно, сортировка слияния на диске, Пример того, как вы делаете это с ленточными накопителями, должен дать вам некоторые рекомендации.