我有如下字符串(这是test1.txt文件的内容):
one
1
</>
two
2
</>
我希望它成为这样的新字符串:
one
1
</>
1
one
</>
two
2
</>
2
two
</>
我使用以下perl oneliner来做到这一点。
perl -pi.bak -e 's#((.*)\n(.*)\n<\/>)#$1\n$3\n$2\n<\/>#g' "test1.txt"
但是它对test1.txt文件没有任何作用。
更新:我都喜欢这三个答案。它们都提供了一些非常有用的信息。在这种情况下,我不确定哪个答案可以接受...
答案 0 :(得分:3)
您正在一次读取一行并与该行匹配,因此您的模式可能无法匹配。
简单的解决方案是使用-0777
(将$/
设置为undef
)将整个文件读取为一行。
perl -i.bak -0777pe's#((.*)\n(.*)\n<\/>)#$1\n$3\n$2\n<\/>#g' test1.txt
答案 1 :(得分:2)
-p
选项按行将输入分配给$_
变量,因此与多行匹配的正则表达式将找不到匹配项。您应先读取整个文件,然后再尝试应用正则表达式:
perl -i.bak -e 'undef $/;$_=<>;s#((.*)\n(.*)\n</>)#$1\n$3\n$2\n</>#g;print' "test1.txt"
在命令行中运行示例:
# perl -e 'undef $/;$_=<>;s#((.*)\n(.*)\n</>)#$1\n$3\n$2\n</>#g;print'<<EOF
> one
> 1
> </>
> two
> 2
> </>
> EOF
one
1
</>
1
one
</>
two
2
</>
2
two
</>
答案 2 :(得分:2)
一根衬里的横截面:
if ( (charCode != 46 && charCode > 31) && (charCode < 48 || charCode > 57)) {
return false;
}
即您的处理循环是基于行的,而您的正则表达式要匹配多行。
注意::我的解决方案使用更通用的过滤器方法STDIN到STDOUT,而不是$ perl -MO=Deparse -pi.bak -e 's#((.*)\n(.*)\n<\/>)#$1\n$3\n$2\n<\/>#g' test.txt
BEGIN { $^I = ".bak"; }
LINE: while (defined($_ = readline ARGV)) {
s[((.*)\n(.*)\n<\/>)][$1\n$3\n$2\n</>]g;
}
continue {
die "-p destination: $!\n" unless print $_;
}
-e syntax OK
。
要么要么将文件保存到内存中,然后应用替换...
-i.bak
...或在标量上下文中将节检测与双稳态范围运算符配合使用:
#!/usr/bin/perl
use warnings;
use strict;
use open qw(:encoding(UTF-8) :std);
my $input;
{
local $/;
$input = <STDIN>;
}
$input =~ s,((.*)\n(.*)\n<\/>),$1\n$3\n$2\n<\/>,g;
print $input;
exit 0;
哪种方法更合适取决于您的实际输入文件或其他处理要求。
试运行:
#!/usr/bin/perl
use warnings;
use strict;
use open qw(:encoding(UTF-8) :std);
my @section;
while (<STDIN>) {
if (/^\w+$/../^<\/>$/) {
push(@section, $_);
}
print;
# End of section reached
if (/^<\/>$/) {
# swivel lines around for desired output result...
print @section[1, 0, 2];
@section = ();
}
}
exit 0;
更新,如果绝对不需要“无重定向”,则可以将$ perl dummy.pl <dummy.txt
one
1
</>
1
one
</>
two
2
</>
2
two
</>
替换为<STDIN>
,以在命令行上处理文件,即
<>
或
my $input = <>;
并在命令行上:
while (<>) {