Как я могу поменять две последовательные строки в Perl? - PullRequest
2 голосов
/ 21 мая 2010

У меня есть эта часть кода для редактирования контрольных листов, и я не знаю, как перевернуть две последовательные строки, если найдены:

/^TITLE.*?"$/  
/^PERFORMER.*?"$/

для возврата к

/^PERFORMER.*?"$/  
/^TITLE.*?"$/  

Каким было бы решение в моем случае?

use strict; 
use warnings; 
use File::Find; 
use Tie::File;


my $dir_target = 'test';

find(\&c, $dir_target);        
sub c {  
   /\.cue$/ or return;

   my $fn = $File::Find::name;

   tie my @lines, 'Tie::File', $fn or die "could not tie file: $!"; 
        for (my $i = 0;  $i < @lines; $i++) {
             if ($lines[$i] =~ /^REM (DATE|GENRE|REPLAYGAIN).*?$/) {
                  splice(@lines, $i, 3);
             }
     if ($lines[$i] =~ /^\s+REPLAYGAIN.*?$/) {
                  splice(@lines, $i, 1);
             }
        }

   untie @lines; 
}

Ответы [ 2 ]

4 голосов
/ 21 мая 2010

Это может показаться излишним, но, учитывая, что ваши файлы не очень большие, я испытываю желание использовать следующую однострочную строку (либо из командной строки, либо через вызов system ).

Однострочник работает, обрезая все строки в одном кадре, а затем оставляя остальную часть работы подстановке регулярных выражений, которая переворачивает порядок строк.

Если вы используете * nix:

perl -0777 -i -ne 's/(TITLE.*?")\n(PERFORMER.*?")/$2\n$1/g' file1 file2 ..

Если вы используете Windows, вам необходимо создать резервную копию существующих файлов:

perl -0777 -i.bak -ne "s/(TITLE.*?\")\n(PERFORMER.*?\")/$2\n$1/g" file1 file2 ..

Объяснение

Командные переключатели (подробнее см. perlrun)

  • -0777 (восьмеричное число) обеспечивает принудительное слежение за файлом
  • -i включает редактирование на месте (нет необходимости splice - 'n'-dice!). Системы Windows требуют, чтобы вы предоставили расширение для резервного копирования, следовательно, дополнительное .bak
  • -n зацикливает все строки в вашем файле (файлах) (хотя, поскольку вы их добавляете, Perl обрабатывает содержимое каждого файла как одну строку)
  • -e позволяет Perl распознавать код в командной строке

Regex

  • Регулярное выражение замещения захватывает все вхождения строки TITLE, последовательной строки PERFORMER и сохраняет ее в переменных $1 и $2 соответственно. Регулярное выражение подстановки переворачивает порядок двух переменных, разделенных новой строкой.

Аргументы имени файла

  • Вы могли бы использовать * nix для предоставления имен файлов соответствующих каталогов, но я оставлю это кому-то другому, чтобы выяснить, так как я пока не слишком разбираюсь в каналах Unix (см. John Siracusa ответ для получения дополнительной информации).

Я бы создал резервную копию ваших файлов, прежде чем вы попробуете эти однострочники.

0 голосов
/ 21 мая 2010

Ну, так как вы связываете массив, я бы просто проверил $lines[$i] и $lines[$i+1] (при условии, что адрес +1 существует), и если первый соответствует TITLE, а второй - PERFORMER поменяй их местами. Если, возможно, вам не нужно переносить их, даже если они не последовательные ??

Вот вариант (этот фрагмент будет идти внутри вашего цикла for, возможно, выше строки проверки REM), если вы знаете, что они будут последовательными:

if ($i < $#lines and $lines[$i] =~ /^TITLE.*?"$/
                 and $lines[$i+1] =~ /^PERFORMER.*?$/) {
    my $tmp = $lines[$i];
    $lines[$i] = $lines[$i+1];
    $lines[$i+1] = $tmp;
}

Другим вариантом (который будет работать независимо от последовательности и, возможно, более элегантно) будет

use List::MoreUtils qw(first_index);

(вверху, с другими вашими use утверждениями), а затем выполните (внутри &c, но вне цикла for):

my $title_idx = first_index { /^TITLE.*?"$/ } @lines;
my $performer_idx = first_index { /^PERFORMER.*?"$/ } @lines;

if($title_idx >= 0 and $performer_idx >= 0 and $title_idx < $performer_idx)
{
    # swap these lines:
    ($lines[$title_idx],$lines[$performer_idx]) =
        ($lines[$performer_idx],$lines[$title_idx]);
}

Это то, что вы ищете?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...