perl多行匹配问题

fam*_*man 21 regex perl

我正在尝试使用perl one-liner更新一些跨越多行的代码并且看到一些奇怪的行为.这是一个简单的文本文件,显示我看到的问题:

ABCD    START
         STOP    EFGH
Run Code Online (Sandbox Code Playgroud)

我期望以下工作,但它不会最终取代任何东西:

perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt
Run Code Online (Sandbox Code Playgroud)

在做了一些实验之后,我发现\s+原始正则表达式将匹配换行符,但不匹配第二行上的任何空格,并且添加秒\s+也不起作用.所以现在我正在做以下的解决方法,即添加一个只删除换行符的中间正则表达式:

perl -pi -e 's/START\s+/START/s' input.txt
Run Code Online (Sandbox Code Playgroud)

这将创建以下中间文件:

ABCD    START            STOP    EFGH
Run Code Online (Sandbox Code Playgroud)

然后我可以运行原始的正则表达式(虽然/s不再需要):

perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt
Run Code Online (Sandbox Code Playgroud)

这将创建最终的所需文件:

ABCD    REPLACE    EFGH
Run Code Online (Sandbox Code Playgroud)

似乎中间步骤似乎不是必要的.我错过了什么吗?

And*_*ndy 23

perl -p一次处理一行文件.你拥有的正则表达式是正确的,但它永远不会与多行字符串匹配.

一个简单的策略,假设文件适合内存,是读取整个事情(没有这样做-p):

$/ = undef;
$file = <>;
$file =~ s/START\s+STOP/REPLACE/sg;
print $file;
Run Code Online (Sandbox Code Playgroud)

注意,我添加了/g修饰符来指定全局替换.

作为所有额外样板的快捷方式,您可以使用现有脚本和-0777选项:perl -0777pi -e 's/START\s+STOP/REPLACE/sg'./g如果您可能需要在文件中进行多次替换,则仍需要添加.

你可能遇到的打嗝,虽然没有这个正则表达式:如果正则表达式是START.+STOP,并且一个文件包含多个START/STOP对,贪婪的匹配.+会吃掉从第一个START到最后一个STOP的所有内容.您可以使用非贪婪匹配(尽可能少匹配).+?.

如果要在字符串中的任何位置使用^$线条边界,那么您还需要/m正则表达式修饰符.

  • 也找不到`-0`的任何信息.那面旗子做什么? (3认同)

tch*_*ist 21

你很亲密 你需要-00-0777:

 perl -0777 -pi -e 's/START\s+/START/' input.txt
Run Code Online (Sandbox Code Playgroud)

  • 什么`-0777`和`-00`呢?我正在阅读perl联机帮助页,但除了这些数字是八进制(很明显)之外,我找不到任何信息.谢谢! (5认同)
  • 选项`-0`改变记录分隔符.`777`激活_slurp mode_,如果没有定义记录分隔符,则立即读取整个文件.`0`将分隔符更改为空行. (3认同)

sai*_*rog 5

一个相对简单的单线程(读取内存中的文件):

perl -pi -e 'BEGIN{undef $/;} s/START\s+STOP/REPLACE/sg;' input.txt
Run Code Online (Sandbox Code Playgroud)

另一种选择(不是那么简单),而不是在内存中读取文件:

perl -ni -e '$a.=$_; \
             if ( $a =~ s/START\s+STOP/REPLACE/s ) { print $a; $a=""; } \
             END{$a && print $a}' input.txt
Run Code Online (Sandbox Code Playgroud)