Regex perl多行匹配问题
我试图使用perl one liner来更新一些跨越多行的代码,并看到一些奇怪的行为。下面是一个简单的文本文件,显示了我看到的问题:Regex perl多行匹配问题,regex,perl,Regex,Perl,我试图使用perl one liner来更新一些跨越多行的代码,并看到一些奇怪的行为。下面是一个简单的文本文件,显示了我看到的问题: ABCD START STOP EFGH 我原以为以下功能会起作用,但它最终不会取代任何功能: perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt 在做了一些实验之后,我发现原始正则表达式中的\s+将匹配换行符,但第二行上的任何空格都不匹配,并且添加第二个\s+也不起作用。现在,我正在
ABCD START
STOP EFGH
我原以为以下功能会起作用,但它最终不会取代任何功能:
perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt
在做了一些实验之后,我发现原始正则表达式中的\s+
将匹配换行符,但第二行上的任何空格都不匹配,并且添加第二个\s+
也不起作用。现在,我正在做以下工作,即添加一个只删除换行符的中间正则表达式:
perl -pi -e 's/START\s+/START/s' input.txt
这将创建以下中间文件:
ABCD START STOP EFGH
然后我可以运行原始正则表达式(尽管不再需要/s
):
这将创建最终的所需文件:
ABCD REPLACE EFGH
似乎不需要中间步骤。我遗漏了什么吗?perl-p一次处理一行文件。您拥有的正则表达式是正确的,但它从未与多行字符串匹配 一个简单的策略是,假设文件适合内存,读取整个内容(在不使用
-p
的情况下执行此操作):
$/=undf;
$file=;
$file=~s/START\s+STOP/REPLACE/sg;
打印$file;
注意,我添加了/g
修饰符来指定全局替换
作为所有额外样板文件的快捷方式,您可以使用带有选项的现有脚本:perl-0777pi-e's/START\s+STOP/REPLACE/sg'
。如果您可能需要在文件中进行多次替换,则仍然需要添加/g
您可能会遇到一个小问题,尽管这个正则表达式不是:如果正则表达式是START.+STOP
,并且一个文件包含多个START/STOP对,那么+
的贪婪匹配将吃掉从第一个开始到最后一个停止的所有东西。您可以对+?
使用非贪婪匹配(尽可能少地匹配)
如果要在字符串中的任何位置使用
^
和$
锚定行边界,则还需要/m
正则表达式修饰符。这里有一个不会将整个文件一次读入内存的单行程序:
perl -MFile::Slurp -e '$content = read_file(shift); $content =~ s/START\s+STOP/REPLACE/s; print $content' input.txt
perl -i -ne 'if (($x = $last . $_) =~ s/START\n\s*STOP/REPLACE/) \
{ print $x; $last = ""; } else { print $last; $last = $_; } \
print $last if eof ARGV' input.txt
一个相对简单的单行程序(读取内存中的文件): 另一种选择(不是那么简单),不读取内存中的文件:
perl -pi -e 'BEGIN{undef $/;} s/START\s+STOP/REPLACE/sg;' input.txt
perl -ni -e '$a.=$_; \
if ( $a =~ s/START\s+STOP/REPLACE/s ) { print $a; $a=""; } \
END{$a && print $a}' input.txt
你很接近。您需要
-00
或-0777
:
perl -0777 -pi -e 's/START\s+/START/' input.txt
您的常见问题在第一句中得到了回答:“perldoc-q match”->“我在多行匹配中遇到问题。出了什么问题?”
/s
只影响匹配的内容,因此,不需要您的/s
为什么您会让人们使用一个非标准模块来完成一个简单的命令行就可以完全处理的事情?那么-0777
和-00
做什么呢?我正在阅读perl手册页,但是除了那些数字是八进制(这是显而易见的),我找不到任何信息。谢谢选项-0
更改记录分隔符777
激活slurp模式,如果没有定义记录分隔符,则s.t.立即读取整个文件0
将分隔符更改为空行。在-0
上也找不到任何信息。那面旗子是干什么的?这让我快发疯了!非常感谢:)很好,虽然我不认为ARGV正在做任何事情,可以删除。
perl -ni -e '$a.=$_; \
if ( $a =~ s/START\s+STOP/REPLACE/s ) { print $a; $a=""; } \
END{$a && print $a}' input.txt
perl -0777 -pi -e 's/START\s+/START/' input.txt