我有一部分用于编辑提示表的代码,如果找到,我不知道如何反转两行:
/^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;
}
答案 0 :(得分:4)
这看起来有点矫枉过正,但是看到你的文件不是很大,我很想利用下面的单行(从命令行或通过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识别命令行中的代码正则表达式
TITLE
行,即连续的PERFORMER
行,并分别将其存储在变量$1
和$2
中。替换正则表达式然后翻转两个变量的顺序,用换行符分隔。文件名参数
在尝试使用这些单行程序之前,我会创建一个文件备份。
答案 1 :(得分:0)
好吧,既然你正在加入一个数组,我只需检查$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]);
}
这就是你要追求的吗?