单行打印两个图案之间的所有线条

时间:2016-03-11 06:53:15

标签: regex perl regex-lookarounds

使用一行Perl代码,在两个模式之间打印所有行的最短路径是什么?不包括带有模式的行?

如果是file.txt:

aaa
START
bbb
ccc
ddd
END
eee
fff

我想打印一下:

bbb
ccc
ddd

我可以使用以下内容获得大部分内容:

perl -ne 'print if (/^START/../^END/);'

但这包括STARTEND行。

我可以像这样完成工作:

perl -ne 'if (/^START/../^END/) { print unless (/^(START)|(END)/); };' file.txt

但这似乎是多余的。

我真正想做的是使用这样的lookbehind和lookahead断言:

perl -ne 'print if (/^(?<=START)/../(?=END)/);' file.txt

但这不起作用,我认为我的正则表达式中有一些错误。

这些只是我试过的一些不产生输出的变体:

perl -ne 'print if (/^(?<=START)/../^.*$(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../^.*(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../.*(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../^.*(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../$(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../^(?=END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../(?=^END)/);' file.txt
perl -ne 'print if (/^(?<=START)/../.*(?=END)/s);' file.txt

4 个答案:

答案 0 :(得分:3)

阅读整个文件,匹配并打印。

perl -0777 -e 'print <> =~ /START.*?\n(.*?)END.*?/gs;' file.txt

如果单独上线,可能会在.*?之后删除START|END。 然后删除\n以获取细分之间的空行。

读取文件,按START|END拆分行,打印每个奇数@F

perl -0777 -F"START|END" -ane 'print @F[ grep { $_ & 1 } (0..$#F) ]' file.txt

使用END { }块进行额外处理。对}{使用END { }

perl -ne 'push @r, $_ if (/^START/../^END/); }{ print "@r[1..$#r-1]"' file.txt

仅适用于文件中的单个此类细分。

答案 1 :(得分:1)

对此设置单行限制似乎有点武断,但这是一种方法:

$ perl -wne 'last if /^END/; print if $p; $p = 1 if /^START/;' file.txt

答案 2 :(得分:1)

perl -e 'print split(/.*START.|END.*/s, join("", <>))' file.txt

perl -ne 'print if /START/../END/' file.txt | perl -ne 'print unless $.==1 or eof'

perl -ne 'print if /START/../END/' file.txt | sed -e '$d' -n -e '1\!p'

答案 3 :(得分:1)

我不明白为什么你如此坚持使用外观,但这里有几种方法可以做到。

perl -ne 'print if /^(?=START)/../^(?=END)/'

这会找到终结符而不实际匹配它们。满足前瞻的零长度匹配是匹配的。

你的lookbehind无法正常工作,因为它试图在^之前找到行START的开头,它在同一行上,显然永远不会匹配。将^计入零宽度断言,它将起作用:

perl -ne 'print if /(?<=^START)/../(?<=^END)/'

根据@ThisSuitIsBlack的评论中的建议,您可以使用序列号省略STARTEND令牌。

perl -ne '$s = /^START/../^END/; print if ($s>1 && $s !~ /E0/)'

看起来没有任何用处,所以我没有完全开发这些例子。如果您更关心使用外观而不是代码可维护性和执行速度,那么您可以将其调整为上面的一个示例。