【问题标题】:Perl: Regex only prints first pattern foundPerl:正则表达式仅打印找到的第一个模式
【发布时间】:2017-09-29 22:11:39
【问题描述】:

我正在尝试解析一个 html 文件,并且我有一个正则表达式,可以捕获所有 p 标签内的模式。由于某种原因,它只打印出找到的第一个实例。

my @newH2Array = ("Part I", "Part II", "Part III");
my $linenumber = 0;
while (my $line = <$parser>){
    chomp $line;
    $linenumber++;
    if($line =~ /^<p>/){
        if($line =~ /(Part [IVX]+)/gi) {
            if (grep{ lc $_ eq lc $1 } @newH2Array){
                print "found a hit <" . $1 . "> that matches array element on line" . $linenumber;
            }
        }
    }
}

当我在下面的这个测试中运行它时,它只会打印出第一部分,而不是其他 3。当我将 if 语句切换到 while 循环时,它也不起作用。谁能告诉我我在这里做错了什么?

<p>Part I should be found. Part II should be found also. Part III should be found.</p>

结果应该是。

found a hit <Part I> that matches array element on line 1
found a hit <Part II> that matches array element on line 1
found a hit <Part III> that matches array element on line 1

【问题讨论】:

  • 您没有使用 HTML 解析器有什么原因吗? For your own good, you shouldn't parse XML with regex.
  • 因为我做了很多编辑,实际上我正在用 unicodes 替换
  • 不过,一旦你完成它就不必阅读它,只有在它或多或少是有效的 HTML 时才需要阅读它。这并不意味着您必须生成有效的 HTML 作为输出。
  • 您的代码丢失$linenumber。那是怎么开始的? 0 还是 1@newH2Array 也不见了。请edit 并提供minimal reproducible example。此外,您不需要在模式中转义尖括号&lt;&gt;,它们没有特殊含义。
  • @simbabque 我编辑了帖子,提供了更多信息。

标签: regex perl


【解决方案1】:

if 语句是二元选择。它要么匹配,要么不匹配。对于一个循环,你需要一个循环结构——比如while

我还使用了say() 而不是print(),Perl 的内置$. 而不是$linenumber,并且我在字符串中插入了变量。

哦,为了便于测试,已切换到 &lt;DATA&gt;

#!/usr/bin/perl

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

my @newH2Array = ("Part I", "Part II", "Part III");
my $linenumber = 0;
while (my $line = <DATA>){
    chomp $line;
    if ($line =~ /^<p>/){
        while ($line =~ /(Part [IVX]+)/gi) {
            if (grep{ lc $_ eq lc $1 } @newH2Array){
                say "found a hit <$1> that matches array element on line $.";
            }
        }
    }
}

__DATA__
<p>Part I should be found. Part II should be found also. Part III should be found.</p>

【讨论】:

  • 太有趣了,我们的答案又几乎相同了。对 TIMTOWTDI 来说就这么多。 :)
  • @simbabque:“伟大的思想是一样的”或者“傻瓜很少不同”:-)
  • 好的,所以我将您的代码复制并粘贴到一个新的 pl 脚本中进行测试,它运行良好。当我用我的正则表达式替换它时,它开始失败。所以我认为我的问题与正则表达式有关。也感谢你让我知道 perl 的内置 $。我这周开始学习 perl 和 regex,所以还有很多东西要学。
  • 是的,我让它工作了,我肯定需要 while 循环,我把它拿出来了,因为我认为 g 标志可能会这样做,但我想不会。我拥有的正则表达式不正确,在我修复它之后,我能够获得所有模式。谢谢你们真的很感激帮助。
【解决方案2】:

您正在使用/g 匹配,但由于if,您只选择了第一个匹配。您需要迭代所有匹配项。一种方法是使用while 循环。

my @newH2Array = ("Part I", "Part II", "Part III", "Part X");

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

    if($line =~ /^<p>/){
        while ($line =~ /(Part [IVX]+)/gi) {
            if (grep{ lc $_ eq lc $1 } @newH2Array){
                print "found a hit <$1> that matches array element on line $.\n";
            }
        }
    }
}

__DATA__
<p>Part I should be found. Part II should be found also. Part III should be found.</p>
<p>Part X should be found. Particles are fun.</p>

请注意,我删除了$linenumber。您可以只使用$.,它始终是最后读取的文件句柄的当前行号。

这是输出。

found a hit <Part I> that matches array element on line 1
found a hit <Part II> that matches array element on line 1
found a hit <Part III> that matches array element on line 1
found a hit <Part X> that matches array element on line 2

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 1970-01-01
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 2022-10-17
    相关资源
    最近更新 更多