首页 > 解决方案 > perl 在两个关键字之间抓取文本

问题描述

我正在尝试阅读两个关键字之间的文本。虽然不是真的工作。我想要的只是阅读问题和答案,然后打印出来。它不起作用,只是继续打印出一个非常大的循环。

#!/usr/bin/perl
use strict ;
use warnings;
my $question ;
my $answer ;

while(my $line = <>){
chomp $line ;

if ($line =~ /questionstart(.*)questionend/) {
    $question = $1 ; }
elsif ($line  =~ /answerstart(.*)answerend/) {
    $answer = $1 ; }

my $flashblock = <<"FLASH" ;
<!-- BEGIN -->
<p class="question">
  $question
</p>
<p class="answer">
   $answer
</p>
<!-- END -->
FLASH
print $flashblock ;
}

这是文件的示例

questionstart

hellphellohellohello


questionend

answerstart

hellohellohello

answerend

标签: perl

解决方案


由于文件是逐行读取的,因此跨越多行的搜索短语永远无法匹配。

解决此问题的一种基本方法是为问答区域设置标志。由于您有进入和离开这些区域的非常清晰的标记,因此代码非常简单

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

my ($question, $answer);
my ($in_Q, $in_A);

while (my $line = <>) {
    next if $line =~ /^\s*$/;

    if    ($line =~ /^\s*questionstart/) { $in_Q = 1; next }   
    elsif ($line =~ /^\s*questionend/)   { $in_Q = 0; next }   
    elsif ($line =~ /^\s*answerstart/)   { $in_A = 1; next }   
    elsif ($line =~ /^\s*answerend/)     { $in_A = 0; next }       

    if    ($in_Q) { $question .= $line }
    elsif ($in_A) { $answer   .= $line }
}

say "Question: $question";
say "Answer: $answer";

if-elsif(为了简洁和强调,我在这里精简了陈述)

这段代码对输入文件做了一些合理的假设。我需要标记开始行(可能有空格),但允许在它们后面添加更多文本。如果您想确保它们是该行中唯一的东西,请在$正则表达式的末尾添加锚点(再次使用\s*)。

据说输入有一个Q/A。如果它曾经更改为多个,则在循环内移动打印,一旦答案结束就这样elsif (/^\s*answerend/) { .. }

问题中的印刷很好,所以我在这里不再重复。如果有机会打印 HTML 以外的格式,则从前导和尾随空格、多个空格和换行符中清除生成的字符串。


对同一个变量的重复测试可能会导致人们寻找一个案例类型的构造,在 Perl 中就是switch。但是,这仍然是一个实验性功能,其运作方式

很难准确描述

(文档!)。此外,它还可能涉及智能匹配,这很难描述,被广泛理解为以当前形式被破坏,并且肯定会改变。所以我建议坚持使用级联 if-elsif 语句(在这种方法中)。


推荐阅读