这个处理多行的perl oneliner不起作用

时间:2019-02-18 05:50:40

标签: regex perl

我有如下字符串(这是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文件没有任何作用。

更新:我都喜欢这三个答案。它们都提供了一些非常有用的信息。在这种情况下,我不确定哪个答案可以接受...

3 个答案:

答案 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 (<>) {