windows 中的 Perl 多行正则表达式

Perl multiline regex in windows

我被这个场景困住了,我有这个regex

*为清楚起见在此处添加的输入:

181221533;MG;3;1476729;<vars>  <vint>    <name>mtest</name> <storedPrecedure>f_sc_mtest</SP>    <base>M_data</base>    <dataType>I</dataType>    <timeMS>17</timeMS>    <ttidr>abc</ttidr>  <base>S</base>    <valor>0</valor>  </vint>  </vars>;889;6;85;112;01/01/2019;29/05/2019 17:17:48
182652972;MG;6314429;740484;<vars>  <vint>    <name>mtest</name>    <sP>f_sc_mtest</sP> <base>sscy</base>    <dataType>I</dataType>    <timeMS>16</timeMS>    <ttidr>abc</Idtype>    <base>S</base>    <valor>4</valor>  </vint></vars>;-1;8;57217;57228;01/01/2019;06/06/2019 22:20:48
182652984;ModeloSP;6314429;740484;<vars>  <vint>     <name>tc_p_act</name>    <sP>rndom_name</sP>    <base>sscyo</base>    <dataType>I</dataType>    <timeMS>0</timeMS>    <Idtype>XYZ</Idtype>    <base>O</base>  </vint>
</vars>;0;;0;41;01/01/2019;06/06/2019 22:31:22

182652988;ModeloSP;6314429;740484;<vars>  <vint>     <name>tc_p_act</name>    <sP>rndom_name</sP>    <base>sscyo</base>    <dataType>I</dataType>    <timeProcess>1</timeProcess>    <Idtype>XYZ</Idtype>    <base>O</base>  </vint>
</vars>;0;;0;85;01/01/2019;06/06/2019 22:37:36

我想在支持多行的 perl 中实现这个正则表达式,因为正如你在示例中看到的那样,记录中有换行符,这个正则表达式搜索 'incomplete' 行(和额外的行)并修复他们(一个 record/line 应该以日期时间结尾)

这就是我正在尝试使用 perl 进行的操作:

perl.exe -0777 -i -pe "s/(?m)^(.*)(>)([\n]+)(<)(.*)([\n]+)(\s*)$/    /igs" "sample.txt"

而且似乎不起作用,我一直收到相同的文本文件。我在便携式 GIT 安装 (v5.34.0)

中使用 perl

有什么我遗漏的吗?

编辑:输出应该是这样的:

181221533;MG;3;1476729;<vars>  <vint>    <name>mtest</name> <storedPrecedure>f_sc_mtest</SP>    <base>M_data</base>    <dataType>I</dataType>    <timeMS>17</timeMS>    <ttidr>abc</ttidr>  <base>S</base>    <valor>0</valor>  </vint>  </vars>;889;6;85;112;01/01/2019;29/05/2019 17:17:48
182652972;MG;6314429;740484;<vars>  <vint>    <name>mtest</name>    <sP>f_sc_mtest</sP> <base>sscy</base>    <dataType>I</dataType>    <timeMS>16</timeMS>    <ttidr>abc</Idtype>    <base>S</base>    <valor>4</valor>  </vint></vars>;-1;8;57217;57228;01/01/2019;06/06/2019 22:20:48
182652984;ModeloSP;6314429;740484;<vars>  <vint>     <name>tc_p_act</name>    <sP>rndom_name</sP>    <base>sscyo</base>    <dataType>I</dataType>    <timeMS>0</timeMS>    <Idtype>XYZ</Idtype>    <base>O</base>  </vint>    </vars>;0;;0;41;01/01/2019;06/06/2019 22:31:22
182652988;ModeloSP;6314429;740484;<vars>  <vint>     <name>tc_p_act</name>    <sP>rndom_name</sP>    <base>sscyo</base>    <dataType>I</dataType>    <timeProcess>1</timeProcess>    <Idtype>XYZ</Idtype>    <base>O</base>  </vint>    </vars>;0;;0;85;01/01/2019;06/06/2019 22:37:36

这似乎产生了想要的输出:

perl.exe -0777 -pe "s: *\n(?=</):    :g;s/\n+/\n/g"
  • 第一个替换将 </ 之前的空格和换行符替换为四个空格。
  • 第二个替换将多个换行符替换为一个换行符。您也可以将其替换为音译:tr/\n//s/s“挤压”换行符。

捕获整个记录并用 space 替换其中的所有换行符,在替换部分使用另一个正则表达式(由 /e 修饰符提供)。然后用一个替换所有多个换行符

perl.exe -0777 -wpe'
    s{ (?:^|\R)\K (\d{9}; .*? \s+\d\d:\d\d:\d\d) }{ =~ s/\n+/ /r}segx; s{\n+}{\n}g
' file.txt

我认为“记录”是:[0-9]{9}; 从 line/file 开始,然后一直到并包括 space 之后的时间戳。记录开始和结束的详细信息应防止这些标签内可能意外模式的意外匹配。

这很麻烦,但我希望它能正确捕获记录,即使某些细节发生变化。


显然上面的方法在 Windows 上失败了,虽然它被确认可以在 Linux 上工作(我现在可以尝试的唯一系统)。

问题一定是在换行中——因此请尝试将匹配项中的 \n 替换为 \R\r\n。特别是在替换部分中嵌入的正则表达式中。或者,为了安全和便携,将 \n 替换为 (\r?\n)(因此回车 return 字符是可选的,不需要为了匹配而存在)。

所以要么

s{ (?:^|\R)\K (\d{9}; .*? \s+\d\d:\d\d:\d\d) }{ =~ s/\R+/ /r}segx; s{\R+}{\r\n}g

s{ (?:^|\R)\K(\d{9};.*?\s+\d\d:\d\d:\d\d) }{ =~ s/(\r\n)+/ /r}segx; s{(\r\n)+}{\r\n}g

但是 \R 应该在 Windows 上匹配它,因此您应该能够使用 \R 进行匹配,并在需要时使用 \r\n 进行替换。在 Misc in perlbackslash

下查看

更好的是,如果它有效,那就是使用 PerlO layers。通常,Perl 的 Windows 构建会默认添加 :crlf 层,但此处似乎并非如此。

在 one-liner 中尝试:

perl.exe -0777 -Mopen=:std,IO,:crlf -wpe'...'

或者,将“one-liner”用作普通程序,不带 file-processing 开关,并通过 open pragma 进行设置并手动打开文件

perl -wE'use open IO => ":crlf"; $_ = do { local $/; <> }; s{...}{...}; say' file

像这样设置图层(以任何一种方式)使用带有 \n 的正则表达式。

如果问题是在错误的地方换行,连续多个换行,或者在 < 之前,您可以通过这样简单的事情来解决问题:

use strict;
use warnings;

my $str = do { local $/; <DATA> };

$str =~ s/\n(?=[<\n])//g;
print $str;

__DATA__
181221533;<valor>0</valor></vars>;889;6;85;112;01/01/2019;29/05/2019 17:17:48
182652972;</vars>;-1;8;57217;57228;01/01/2019;06/06/2019 22:20:48
182652984;</vint>
</vars>;0;;0;41;01/01/2019;06/06/2019 22:31:22

182652988; </vint>
</vars>;0;;0;85;01/01/2019;06/06/2019 22:37:36

(我缩短了输入以使其可读)

输出:

181221533;<valor>0</valor></vars>;889;6;85;112;01/01/2019;29/05/2019 17:17:48
182652972;</vars>;-1;8;57217;57228;01/01/2019;06/06/2019 22:20:48
182652984;</vint></vars>;0;;0;41;01/01/2019;06/06/2019 22:31:22
182652988; </vint></vars>;0;;0;85;01/01/2019;06/06/2019 22:37:36