正则表达式捕获从特定表达式到 Perl 中第一个空行的多行

Regex to capture multilines from specific expression until first blank line in Perl

我有这个文件,我想匹配#sent_id=\d+ 和空白行之间的所有内容。 这是我的文件:

# newdoc
# newpar
# sent_id = 1
# text = 2019, un bon cru pour les amateurs de technologie.
1   2019    2019    NUM _   _   5   nummod  _   SpaceAfter=No
2   ,   ,   PUNCT   _   _   1   punct   _   _
3   un  un  DET _   Definite=Ind|Gender=Masc|Number=Sing|PronType=Art   5   det _   _
4   bon bon ADJ _   Gender=Masc|Number=Sing 5   amod    _   _
5   cru cru NOUN    _   Gender=Masc|Number=Sing 0   root    _   _
6   pour    pour    ADP _   _   8   case    _   _
7   les le  DET _   Definite=Def|Gender=Masc|Number=Plur|PronType=Art   8   det _   _
8   amateurs    amateur NOUN    _   Gender=Masc|Number=Plur 5   nmod    _   _
9   de  de  ADP _   _   10  case    _   _
10  technologie technologie NOUN    _   Gender=Fem|Number=Sing  8   nmod    _   SpaceAfter=No
11  .   .   PUNCT   _   _   5   punct   _   SpacesAfter=\n

# sent_id = 2
# text = L’année a été généreuse en innovations prometteuses. Voici les six tendances qui pourraient bousculer notre paysage technologique.
1   L’  L’  PROPN   _   _   5   nsubj   _   SpaceAfter=No
2   année   année   NOUN    _   Gender=Fem|Number=Sing  1   nmod    _   _
3   a   avoir   AUX _   Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin   5   aux:tense   _   _
4   été être    AUX _   Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part    5   cop _   _
5   généreuse   généreux    ADJ _   Gender=Fem|Number=Sing  0   root    _   _
6   en  en  ADP _   _   7   case    _   _
7   innovations innovation  NOUN    _   Gender=Fem|Number=Plur  5   obl _   _
8   prometteuses    prometteur  ADJ _   Gender=Fem|Number=Plur  7   amod    _   SpaceAfter=No
9   .   .   PUNCT   _   _   10  punct   _   _
10  Voici   voici   VERB    _   _   5   parataxis   _   _
11  les le  DET _   Definite=Def|Gender=Fem|Number=Plur|PronType=Art    13  det _   _
12  six six NUM _   _   13  nummod  _   _
13  tendances   tendance    NOUN    _   Gender=Fem|Number=Plur  10  obj _   _
14  qui qui PRON    _   PronType=Rel    15  nsubj   _   _
15  pourraient  pouvoir VERB    _   Mood=Cnd|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin   13  acl:relcl   _   _
16  bousculer   bousculer   VERB    _   VerbForm=Inf    15  xcomp   _   _
17  notre   son DET _   Gender=Masc|Number=Sing|Poss=Yes|PronType=Prs   18  det _   _
18  paysage paysage NOUN    _   Gender=Masc|Number=Sing 16  obj _   _
19  technologique   technologique   ADJ _   Gender=Masc|Number=Sing 18  amod    _   SpaceAfter=No
20  .   .   PUNCT   _   _   5   punct   _   SpacesAfter=\n

# sent_id = 3
# text = A Hongkong, des centaines d’arrestations lors d’affrontements, une situation qui semble « désespérée ».
1   A   à   ADP _   _   2   case    _   _
2   Hongkong    Hongkong    PROPN   _   _   0   root    _   SpaceAfter=No
3   ,   ,   PUNCT   _   _   2   punct   _   _
4-5 des _   _   _   _   _   _   _   _
4   de  de  ADP _   _   6   case    _   _
5   les le  DET _   Definite=Def|Gender=Fem|Number=Plur|PronType=Art    6   det _   _
6   centaines   centaine    NOUN    _   Gender=Fem|Number=Plur  2   nmod    _   _
7   d’  d’  PROPN   _   _   6   appos   _   SpaceAfter=No
8   arrestations    arrestation NOUN    _   Gender=Fem|Number=Plur  7   flat:name   _   _
9   lors    lors    ADV _   _   10  case    _   _
10  d’  d’  PROPN   _   _   6   nmod    _   SpaceAfter=No
11  affrontements   affrontement    NOUN    _   Gender=Masc|Number=Plur 10  flat:name   _   SpaceAfter=No
12  ,   ,   PUNCT   _   _   14  punct   _   _
13  une un  DET _   Definite=Ind|Gender=Fem|Number=Sing|PronType=Art    14  det _   _
14  situation   situation   NOUN    _   Gender=Fem|Number=Sing  10  appos   _   _
15  qui qui PRON    _   PronType=Rel    16  nsubj   _   _
16  semble  sembler VERB    _   Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin   14  acl:relcl   _   _
17  «   «   PUNCT   _   _   18  punct   _   SpacesAfter= 
18  désespérée  désespéré   ADJ _   Gender=Fem|Number=Sing  16  xcomp   _   SpacesAfter= 
19  »   »   PUNCT   _   _   18  punct   _   SpaceAfter=No
20  .   .   PUNCT   _   _   10  punct   _   SpacesAfter=\n

# sent_id = 4
# text = Des dizaines de milliers de personnes ont défilé dans la mégapole. « C’est triste que nos revendications de 2019 doivent être reportées à 2020 », a souligné un des organisateurs.
1-2 Des _   _   _   _   _   _   _   _
1   De  de  ADP _   _   3   case    _   _
2   les le  DET _   Definite=Def|Gender=Fem|Number=Plur|PronType=Art    3   det _   _
3   dizaines    dizaine NOUN    _   Gender=Fem|Number=Plur  9   nsubj   _   _
4   de  de  ADP _   _   5   case    _   _
5   milliers    millier NOUN    _   Gender=Masc|Number=Plur 3   nmod    _   _
6   de  de  ADP _   _   7   case    _   _
7   personnes   personne    NOUN    _   Gender=Fem|Number=Plur  5   nmod    _   _
8   ont avoir   AUX _   Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin   9   aux:tense   _   _
9   défilé  défiler VERB    _   Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part    31  ccomp   _   _
10  dans    dans    ADP _   _   12  case    _   _
11  la  le  DET _   Definite=Def|Gender=Fem|Number=Sing|PronType=Art    12  det _   _
12  mégapole    mégapole    NOUN    _   Gender=Fem|Number=Sing  9   obl:arg _   SpaceAfter=No
13  .   .   PUNCT   _   _   17  punct   _   _
14  «   «   PUNCT   _   _   17  punct   _   SpacesAfter= 
15  C’  C’  PROPN   _   _   17  nsubj   _   SpaceAfter=No
16  est être    AUX _   Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin   17  cop _   _
17  triste  triste  ADJ _   Gender=Masc|Number=Sing 9   xcomp   _   _
18  que que SCONJ   _   _   23  mark    _   _
19  nos son DET _   Gender=Fem|Number=Plur|Poss=Yes|PronType=Prs    20  det _   _
20  revendications  revendication   NOUN    _   Gender=Fem|Number=Plur  23  nsubj   _   _
21  de  de  ADP _   _   22  case    _   _
22  2019    2019    NUM _   _   20  nmod    _   _
23  doivent devoir  VERB    _   Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin   17  ccomp   _   _
24  être    être    AUX _   VerbForm=Inf    25  aux:pass    _   _
25  reportées   reporter    VERB    _   Gender=Fem|Number=Plur|Tense=Past|VerbForm=Part 23  xcomp   _   _
26  à   à   ADP _   _   27  case    _   _
27  2020    2020    NUM _   _   25  obl:arg _   SpacesAfter= 
28  »   »   PUNCT   _   _   17  punct   _   SpaceAfter=No
29  ,   ,   PUNCT   _   _   9   punct   _   _
30  a   avoir   AUX _   Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin   31  aux:tense   _   _
31  souligné    souligner   VERB    _   Gender=Masc|Number=Sing|Tense=Past|VerbForm=Part    0   root    _   _
32  un  un  PRON    _   Gender=Masc|Number=Sing 31  nsubj   _   _
33-34   des _   _   _   _   _   _   _   _
33  de  de  ADP _   _   35  case    _   _
34  les le  DET _   Definite=Def|Gender=Masc|Number=Plur|PronType=Art   35  det _   _
35  organisateurs   organisateur    NOUN    _   Gender=Masc|Number=Plur 32  nmod    _   SpaceAfter=No
36  .   .   PUNCT   _   _   31  punct   _   SpacesAfter=\n

我想捕获 #sent_id 和新的 #sent_id 之间的所有内容。

我试过了,但它与所有文件匹配。

sub extract_dependancies{

    open my $fh, "<:encoding(utf-8)", shift or die "$!\n";
    undef $/;
    my $file = <$fh>;
   # sent_id to blank line
    while($file =~ /^#\ssent.+\d+(.+)^$/msg){
        my $sentence = ;
        #next if $sentence !~ /d+\tobj/;
    }
}

标量语句检索所有文件。我想逐句逐句。句子应该包含两个#sent_id之间的内容,像这样。

# text = 2019, un bon cru pour les amateurs de technologie.
1   2019    2019    NUM _   _   5   nummod  _   SpaceAfter=No
2   ,   ,   PUNCT   _   _   1   punct   _   _
3   un  un  DET _   Definite=Ind|Gender=Masc|Number=Sing|PronType=Art   5   det _   _
4   bon bon ADJ _   Gender=Masc|Number=Sing 5   amod    _   _
5   cru cru NOUN    _   Gender=Masc|Number=Sing 0   root    _   _
6   pour    pour    ADP _   _   8   case    _   _
7   les le  DET _   Definite=Def|Gender=Masc|Number=Plur|PronType=Art   8   det _   _
8   amateurs    amateur NOUN    _   Gender=Masc|Number=Plur 5   nmod    _   _
9   de  de  ADP _   _   10  case    _   _
10  technologie technologie NOUN    _   Gender=Fem|Number=Sing  8   nmod    _   SpaceAfter=No
11  .   .   PUNCT   _   _   5   punct   _   SpacesAfter=\n

第一句等等。但是我要么捕获所有文件,要么什么都不捕获。

一种方法:以空行之间的文本块读取文件。

use warnings;
use strict;
use feature 'say';

die "Usage: [=10=] file\n" if not @ARGV;

my @sentences;

# First pass lines until the first  "# sent_id =..." (and that one)
while (<>) { last if /^\s*#\s*sent_id/ }

local $/ = "\n\n";  # read in blocks of up to an empty line

while (<>) {
    # Remove the leading line "# sent_id =...", return the rest
    push @sentences, s{ ^ \#\s* sent_id\s* = \s*[0-9]+ .*?\n }{}xr;
}

say for @sentences;

第一个 while <> 用于到达并通过第一个 sent_id 行。然后下一个 while (<>) 从第一个停止的地方开始,并以空行分隔的块为单位读取文件。

每个块中的第一行 sent_id 被匹配并删除,而其余部分被 returned(通过 "non-destructive" /r 修饰符)和添加到数组中。

这会在每个“句子”中保留尾随的空行,如果需要可以轻松删除。

我使用神奇的 "null filehandle" <> 读取文件并在主程序中为简单起见完成所有操作,但请务必将其放在问题中的一个很好的子例程中。然后它可以 return 引用 @sentences.

注意解释器中所有代码的 local, which in a short program like above doesn't matter but is crucial to use in general; with it the global variable on which it is applied (here $/) is restored upon leaving the scope. The code in the question changes the global $/ variable


或按照要求和尝试使用正则表达式解析文件。

一种方法:使用 # sent_id = ... 行作为标记进行迭代

use warnings;
use strict; 
use feature 'say';

die "Usage: [=11=] file\n" if not @ARGV;

my $content = do { local $/; <> };

my @sentences;

while ( $content =~ / \#\s* sent_id \s*=\s* [0-9]+ .*? \n /gx ) {
    push @sentences, $content =~ /\G (.*?) (?:\n\n|$)/sx;
    #say "pos = ", pos $content;
}

say for @sentences;

\G 锚定到上一个与 /g 修饰符匹配的位置。所以带有它的模式(在 push... 行中)从 while 条件中的模式匹配之后开始匹配,所以它匹配从上一个 # sent_id... 行之后到下一个空行的所有内容行。

请参阅文档以了解 /g\G 的组合如何工作以及如何使用,例如 "Global Matching" in perlretut

或者,一次搞定一切

use warnings;
use strict;
use feature 'say';

die "Usage: [=12=] file\n" if not @ARGV;

my $content = do { local $/; <> };

my @sentences = 
    $content =~ / \#\s*sent_id\s*=\s*[0-9]+ .*?\n (.+?) (?:\n\n|$) /gsx;

say for @sentences;

我认为这是最棘手和最不可靠的解决方案。

请调查以下解决方案是否符合您的任务

  • 定义局部记录结束在空行
  • map 循环中从 <> 读取记录
  • 利用正则表达式只捕获您感兴趣的内容
  • 将结果存储在 @blocks 数组中
  • 显示 @blocks 个具有 say 的元素(可选)

注意:运行 为 ./script.pl datafile

use strict;
use warnings;
use feature 'say';

my @blocks;

{
    local $/ = "\n\n";
    @blocks = map { /(# sent_id = .*)/s } <>;
}

say for @blocks;

perl -ne '$f=0 if /sent_id/; print "$_" if $f; $f=1 if /sent_id/' french.in > french.out

这个单行捕获了一个 #sent_id 和下一个 #sent_id 之间的所有内容。

它是如何工作的:

perl -MO=Deparse -ne '$f=0 if /sent_id/; print "$_" if $f; $f=1 if /sent_id/' french.in

LINE: while (defined($_ = readline ARGV)) {
    $f = 0 if /sent_id/;
    print "$_" if $f;
    $f = 1 if /sent_id/;
}

在处理第一行时,标签 #sent_id = 1 被匹配并将 $f 切换到假状态:$f=0 if /sent_id/;

下一条语句print "$_" if $f因此不会执行。

然后,在第一行还在处理的时候,标签#sent_id = 1再次被匹配,并且切换$f为真状态:$f=1 if /sent_id/;

while循环进入下一次迭代,移动到下一行:"# text = 2019, un bon cru pour les amateurs de technologie."

由于 $f 现在处于真实状态,因此将打印此行以及以下行,直到以标记 # sent_id = 2.

开头的行

此处 $f 再次切换到 false 状态:$f = 0 if /sent_id/; 并且下一条语句 print "$_" if $f 未执行。仍然在同一行上,标签 # sent_id = 2 再次匹配并将 $f 变为真实状态:$f = 1 if /sent_id/;

现在 while 循环移动到下一行: "# text = L’année a été généreuse en innovations prometteuses. ..." 因为 $f 现在处于真实状态,这一行和后面的行(在标签 # sent_id = 3) 被打印出来。