如何使perl单线"线端不可知"

Cha*_*esB 5 regex perl newline

我在perl oneliner上失败了一个小时,因为文件有CRLF行结尾.它在行尾有一个带有组匹配的正则表达式,并且CR包含在匹配中,使用反向引用替换是坏事.

我最终在正则表达式中手动指定了CRLF,但有没有办法让perl句柄自动换行,无论它们是什么?

原来的命令是

perl -pe  's/foo bar(.*)$/foo $1 bar/g' file.txt
Run Code Online (Sandbox Code Playgroud)

"正确"命令是

perl -pe  's/foo bar(.*)\r\n/foo $1 bar\r\n/g' file.txt
Run Code Online (Sandbox Code Playgroud)

我知道我也可以在处理之前转换行结尾,我很感兴趣如何让Perl优雅地处理这个案例.

示例文件(使用CRLF行结尾保存!)

[19:06:57.033] foo barmy
[19:06:57.033] foo baryour
Run Code Online (Sandbox Code Playgroud)

预期产出

[19:06:57.033] foo my bar
[19:06:57.033] foo your bar
Run Code Online (Sandbox Code Playgroud)

使用原始命令输出(bar开始在行开始,因为它与回车匹配):

bar:06:57.033] foo my
bar:06:57.033] foo your
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 6

首先,让我们记住这一点

perl -ple's/foo bar(.*)\z/foo $1 bar/g' file.txt
Run Code Online (Sandbox Code Playgroud)

是接近的东西的缩写

perl -e'
   while (<>) {
      chomp;
      s/foo bar(.*)\z/foo $1 bar/g;
      print $_, $/;
   }
' file.txt
Run Code Online (Sandbox Code Playgroud)

Perl使得代码可以以独立于平台的方式读/写本地文本文件.

在评论中,您询问了如何以独立于平台的方式读取/写入本地文本文件和外部文本文件.

首先,您必须禁用Perl的正常处理.

binmode STDIN;
binmode STDOUT;
Run Code Online (Sandbox Code Playgroud)

然后你将不得不处理多行结尾.

sub mychomp { (@_ ? $_[0] : $_) =~ s/(\s*)\z//; $1 }

while (<STDIN>) {
   my $le = mychomp($_);
   s/foo bar(.*)\z/foo $1 bar/g;
   print($_, $le);
}
Run Code Online (Sandbox Code Playgroud)

而不是

perl -ple's/foo bar(.*)\z/foo $1 bar/g' file.txt
Run Code Online (Sandbox Code Playgroud)

你将会拥有

perl -e'
   sub mychomp { (@_ ? $_[0] : $_) =~ s/(\s*)\z//; $1 }

   binmode STDIN;
   binmode STDOUT;
   while (<STDIN>) {
      my $le = mychomp($_);
      s/foo bar(.*)\z/foo $1 bar/g;
      print($_, $le);
   }
' <file
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 1

转义\R序列 Perl v5.10+;请参阅perldoc rebackslash在线文档,它与“通用换行符”(平台无关)相匹配, 可以在此处工作(示例使用 Bash 创建多行输入字符串):

$ printf 'foo barmy\r\nfoo baryour\r\n' | perl -pe 's/foo bar(.*?)\R/foo $1 bar\n/gm'
foo my bar
foo your bar
Run Code Online (Sandbox Code Playgroud)

请注意,与Ether 答案的唯一区别是使用非贪婪构造.*?而不仅仅是.*),这使得这里出现了所有的差异。

如果您想了解更多信息,请继续阅读。


背景:

这是与 相关的陷阱\R的一个例子,它源于这样一个事实:它可以匹配一个或两个字符-\r\n或者,通常是\n[1]

使用贪婪(.*)构造 ,"my\r"-包括-\r被捕获,因为正则表达式引擎显然只回溯一个字符来查找\R,而其余字符\n 本身也满足这一要求。

相比之下,使用非贪婪(.*?)构造会导致按照预期\R匹配\r\n 序列

[1]\R不仅仅匹配\r\nand\n:它匹配 Unicode 术语中分类为垂直空白的任何单个字符,其中还包括\v(垂直\f制表符)、(换页符)、\r(单独)以及以下 Unicode 字符:0x133 (NEXT LINE)0x2028 (LINE SEPARATOR)0x8232 (LINE SEPARATOR)0x8233 (PARAGRAPH SEPARATOR)