Windows中的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中实现这个正则表达式,因为正如您在示例中所看到的,记录中有换行符,并且此正则表达式搜索"不完整"的行(和额外的行)并修复它们(一条记录/行应以日期时间结尾)

这是我正在尝试使用 Perl 的:

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

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

我错过了什么吗?

编辑:这是输出的样子:

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

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

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

我认为"记录"是:[0-9]{9};行/文件开头,然后全部到空格后并包括时间戳。 记录开头和结尾的详细信息应防止意外匹配这些标记中可能的意外模式。

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


显然,上述内容在Windows上失败,而已确认可以在Linux上运行(我现在唯一可以尝试的系统)。

问题必须在换行符中 - 因此请尝试将比赛中的n替换为Rrn。 特别是在嵌入在替换部件中的正则表达式中。或者,为了安全且便携,请将n替换为(r?n)(因此回车符是可选的,不需要为了匹配而存在)。

所以要么

s{ (?:^|R)K (d{9}; .*? s+dd:dd:dd) }{$1 =~ s/R+/ /r}segx; s{R+}{rn}g

s{ (?:^|R)K(d{9};.*?s+dd:dd:dd) }{$1 =~ s/(rn)+/ /r}segx; s{(rn)+}{rn}g

但是R应该在 Windows 上匹配它,因此您应该能够在替换中使用R进行匹配和rn。在 Perlbackslash 中的杂项下看到它


更好的是,如果它有效,就是使用PerlO层。通常,Perl的Windows版本默认添加:crlf层,但这里似乎并非如此。

在单行尝试中:

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

或者,使用"单行"作为普通程序,没有文件处理开关,并通过打开杂注进行设置并手动打开文件

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

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

perl.exe -0777 -pe "s: *n(?=</):    :g;s/n+/n/g"
  • 第一个替换替换空格,后跟换行符,然后</四个空格。
  • 第二个替换将多个换行符替换为单个换行符。您也可以将其替换为音译:tr/n//s/s"挤压"换行符。

最新更新