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

问题描述 投票:1回答:3

我有这个字符串如下(这是test1.txt文件的内容):

one
1
</>
two
2
</>

我希望它成为一个像这样的新字符串:

one
1
</>
1
one
</>
two
2
</>
2
two
</>

我使用以下perl one liner来做到这一点。

perl -pi.bak -e 's#((.*)\n(.*)\n<\/>)#$1\n$3\n$2\n<\/>#g' "test1.txt"

但它对test1.txt文件没有任何作用。

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

regex perl
3个回答
3
投票

您正在一次读取一行并与该行匹配,因此您的模式可能无法匹配。

简单的解决方案是使用-0777(将$/设置为undef)将整个文件作为一行读取。

perl -i.bak -0777pe's#((.*)\n(.*)\n<\/>)#$1\n$3\n$2\n<\/>#g' test1.txt

2
投票

您的一个班轮的剖面:

$ 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

即你的处理循环是基于行的,而你的正则表达式想要匹配多行。

注意:我的解决方案使用更通用的过滤方法STDIN到STDOUT,而不是-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 (<>) {

并在命令行上:

$ perl -i.bak dummy.pl test1.txt

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
</>
© www.soinside.com 2019 - 2024. All rights reserved.