正则表达式 匹配行并另存为第一行



嗨,我一直在尝试编写一个 REGEX 来匹配开始"步骤开始"和"步骤结束"之间的文本,然后使用步骤开始后的第一行将文件另存为,但我似乎无法让 REGEX 工作。我正在使用Perl来做到这一点,但我也可以使用JavaScript函数。

正则表达式

^step startR(w.+w)R(w.+w)+step end

示例数据

step start
Block 1+
DMC-GAASIB0-00-48-21-02-01AAA-520A-A.xml
DMC-GAASIB0-00-48-21-02-01AAA-720A-A.xml
step end
step start
4026 through 4167 and 4170 through 4207
DMC-GAASIB0-00-79-11-01-00AAA-941A-A.xml
step end
4108 through 4124 and Block 1+
DMC-GAASIB0-00-91-28-00-19AAA-051A-A.xml
step end
step start
4242 through 4606
DMC-GAASIB0-03-48-21-02-01AAA-520A-A.xml
DMC-GAASIB0-03-48-21-02-01AAA-720A-A.xml
step end
step start
Aircraft 4010 through 4124
DMC-GAASIB0-00-08-41-01-00AAA-169F-A.xml
DMC-GAASIB0-00-08-41-03-00AAA-023A-A.xml
DMC-GAASIB0-00-91-93-7A-12AAA-051A-A.xml
step end

谢谢你的帮助。

您需要在重复组中包含R并使其懒惰以避免匹配重叠的开始/结束块:

^step startR(w.+)R(?:w.+R)*?step end$

正则表达式演示

非捕获组(?:w.+R)*?允许在末尾换行,以允许在匹配step end之前匹配多行

step end后使用$也是安全的。

我建议先匹配整个中间的文本块,然后提取第一行。否则,您的w.+w模式可能会无意中匹配step end并跳到下一个块。例如

step start
step end
step start
foo
bar.xml
step end

否则将被解析为文件名(第一行(为step end的单个块。

if ($string =~ /^step startn(.*?)^step end$/ms) {
my $block = $1;
my $first_line;
if ($block =~ s/A(.*)n//) {
$first_line = $1;
}
...
}

在这里,.*?模式(与s标志相结合(与"任何文本,但尽可能少"匹配。

或者,您可以在"nstep endn"上拆分输入并从每个块中删除标头:

for my $block (split /^step endn/m, $string) {
$block =~ s/Astep startn(.*)n//
or next;  # malformed block
my $first_line = $1;
...
}

我的观点是,对于您正在做的事情来说,直接的正则表达式解决方案不够健壮。首先,它似乎要求您在尝试匹配之前将整个文件放入内存中,这无法扩展到大型输入。这是一个一次性解决方案,它不会使文件名带有空格(替换为_(:

perl -ne '
if($n==1){
($f=$_)=~s/s/_/g;
chop $f;
open F,">$f";
}
if(/^step start/){
$n=1;
}
elsif(!/^step end/){
print F $_;
++$n;
}'

相关内容

最新更新