首页 > 解决方案 > perl 多行正则表达式来分隔段落中的注释

问题描述

下面的脚本有效,但它需要一个 kludge。“kludge”是指使脚本执行我想要的操作的一行代码 --- 但我不明白为什么该行是必要的。显然,我不明白多行正则表达式替换的确切含义,结尾/mg是在做什么。

难道没有更优雅的方式来完成任务吗?

该脚本逐段读取文件。它将每个段落分成两个子集:$text$cmnt。包括每行的$text左边部分,即从第一列到第一列%(如果存在),或者到行尾(如果不存在)。$cmnt包括其余的。

动机:要阅读的文件是 LaTeX 标记,其中%宣布评论的开始。如果我们通过 perl 脚本读取,我们可以将 的值更改$breaker为相等。#从 分离$text$cmnt,可以跨行执行匹配,例如

print "match" if ($text =~ /WOLF\s*DOG/s);

请参阅标有“kludge”的行。%没有那条线,在唱片的最后一条之后会发生一些有趣的事情。如果在记录的最后一个注释行之后有行$text (材料未注释掉%),则这些行包含在末尾$cmnt和中$text

在下面的示例中,这意味着没有 kludge,在记录 2 中,“cat lion”既包含$text在它所属的 中,也包含在 中$cmnt

(kludge 导致一个不必要%的出现在每个 non-void 的末尾$cmnt。这是因为 kludge-pasted-on%宣布了一个最终的、虚构的空注释行。)

根据https://perldoc.perl.org/perlre.html#Modifiers/m正则表达式修饰符意味着

将匹配的字符串视为多行。也就是说,将“^”和“$”从匹配字符串第一行的开头和最后一行的结尾更改为匹配字符串中每一行的开头和结尾。

因此,我期待第二场比赛

s/^([^$breaker]*)($breaker.*?)$/$2/mg

从第一个开始%,一直延伸到行尾,然后停在那里。所以即使没有kludge,它也不应该在记录2中包括“猫狮”?但显然它确实如此,所以我误读或遗漏了文档的某些部分。我怀疑它与/g正则表达式修饰符有关?

#!/usr/bin/perl
use strict; use warnings;
my $count_record = 0;
my $breaker = '%';
$/ = ''; # one paragraph at a time
while(<>)
{
    $count_record++; 
    my $text = $_; 
    my $cmnt;
    s/[\n]*\z/$breaker/; # kludge
    s/[\n]*\z/\n/; # guarantee each record ends with exactly one newline==LF==linefeed
    if ($text =~ s/^([^$breaker]*)($breaker.*?)$/$1/mg)  # non-greedy
    {
        $cmnt    = $_; 
        die "cmnt does not match" unless ($cmnt =~ s/^([^$breaker]*)($breaker.*?)$/$2/mg);  # non-greedy
    }
    else
    {
        $cmnt    = ''; 
    }
    print "\nRECORD $count_record:\n";
    print "******** text==";
    print "\n|";
    print $text;
    print "|\n";
    print "******** cmnt==|";
    print $cmnt;
    print "|\n";
}

运行它的示例文件:

dog wolf % flea 
DOG WOLF % FLEA 
DOG WOLLLLLLF % FLLLLLLEA 


% what was that?
 cat lion


no comments in this line




%The last paragraph of this file is nothing but a single-line comment.

标签: regexperlmultilinestring-substitution

解决方案


您还必须删除不包含以下注释的行$cmnt

use feature qw(say);
use strict;
use warnings;

my $count_record = 0;
my $breaker = '%';
$/ = ''; # one paragraph at a time
while(<>)
{
    $count_record++;
    my $text = $_;
    my $cmnt;
    s/[\n]*\z/\n/; # guarantee each record ends with exactly one newline==LF==linefeed
    if ($text =~ s/^([^$breaker]*)($breaker.*?)$/$1/mg)  # non-greedy
    {
        $cmnt    = $_;
        $cmnt =~ s/^[^$breaker]*?$//mg;
        die "cmnt does not match" unless ($cmnt =~ s/^([^$breaker]*)($breaker.*?)$/$2/mg);  # non-greedy
    }
    else
    {
        $cmnt    = '';
    }
    print "\nRECORD $count_record:\n";
    print "******** text==";
    print "\n|";
    print $text;
    print "|\n";
    print "******** cmnt==|";
    print $cmnt;
    print "|\n";
}

输出

RECORD 1:
******** text==
|dog wolf 
DOG WOLF 
DOG WOLLLLLLF 

|
******** cmnt==|% flea 
% FLEA 
% FLLLLLLEA 
|

RECORD 2:
******** text==
|
 cat lion

|
******** cmnt==|% what was that?

|

RECORD 3:
******** text==
|no comments in this line

|
******** cmnt==||

RECORD 4:
******** text==
||
******** cmnt==|%The last paragraph of this file is nothing but a single-line comment.
|

推荐阅读