【发布时间】:2019-04-18 01:31:16
【问题描述】:
使用一行 Perl 代码,打印两个模式之间的所有行(不包括带有模式的行)的最短方法是什么?
如果这是file.txt:
aaa
START
bbb
ccc
ddd
END
eee
fff
我想打印这个:
bbb
ccc
ddd
我可以使用这样的方式到达那里的大部分路:
perl -ne 'print if (/^START/../^END/);'
不过,这包括 START 和 END 行。
我可以这样完成工作:
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
【问题讨论】:
-
查看perlop中关于序列号的部分:perldoc.perl.org/perlop.html#Range-Operators
-
@ThisSuitIsBlackNot 谢谢。我看到“您可以通过等待序列号大于1来排除起点。”这允许我使用
perl -ne 'print if ((/^START/../^END/) > 1);' file.txt跳过打印第一个模式,但它不是固定的行数,所以我不能排除范围内的最后一个模式。 -
"范围内的最终序列号附加了字符串
E0,这不会影响其数值,但如果您想排除端点,则可以搜索一些内容。 " -
@ThisSuitIsBlackNot 哈!谢谢 :) 我在您链接的页面上看到了它,直到现在才注册它的含义。在尝试对其进行测试时,我使用的是
printf("%d\n"),所以我没有看到E0。现在我有perl -ne '$s = /^START/../^END/; print if ($s > 1 && $s !~ /E0/);' file.txt。它比我的unless版本更有效且更短,但我真的希望它能够与 lookarounds 一起使用。 -
使用环视,您需要阅读整个文本并使用
/(?<=^START\n)(?:(?!^END$).)*/sm之类的内容。缓和的贪婪令牌与未锚定的后视相结合实际上是一种过度杀伤,如果输入很大,这是一种非常低效的方法。
标签: regex perl regex-lookarounds