使用Perl正则表达式提取具有内部和最外边界的文本

时间:2013-09-26 07:32:38

标签: regex perl

以这两个文本为例

my $line = "[cytokine]<ADJVNT-PROP-0> signaling, which have not [to]<PREP> date been shown [to]<PREP> be [[regulat]<EXP-V-0>ed]<EXP-PP-V-0>";
my $line2 = "[Human [papillomavirus]<VACC-PROP-0>]<VACC-PROP-0> genotype [31]<NUM> does not [express]<EXP-V-0> detectable [microRNA]<MIR-0> levels [during]<PREP> latent or productive virus replication.";

我要做的是提取所有受<VAC<ADJ<EXP限制的字符串 在有多个匹配的左侧从最里面提取字符串 直到最右边,直到最远。

例如上面的结果我想要一个返回这些的正则表达式:

Output1: signaling, which have not [to]<PREP> date been shown [to]<PREP> be [[regulat]<EXP-V-0>ed]
Output2: genotype [31]<NUM> does not [express]

为什么此代码不起作用:

my @lines = ("[cytokine]<ADJVNT-PROP-0> signaling, which have not [to]<PREP> date been shown [to]<PREP> be [[regulat]<EXP-V-0>ed]<EXP-PP-V-0>",
"[Human [papillomavirus]<VACC-PROP-0>]<VACC-PROP-0> genotype [31]<NUM> does not [express]<EXP-V-0> detectable [microRNA]<MIR-0> levels [during]<PREP> latent or productive virus replication.");


my $count = 0;
foreach $line (@lines) {
    $count++;
    my ($sel) = $line =~ /<VAC|<ADJ.*>(.*)<EXP.*>/;
    print "Output $count: $sel\n";

}

可执行文件:https://eval.in/50772

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

首先你的OR运算符的范围是错误的:

/<VAC|<ADJ.*>(.*)<EXP.*>/

这将匹配<VAC<ADJ.*>(.*)<EXP.*>。将所需部分包裹在非捕获组周围:

/<(?:VAC|ADJ).*>(.*)<EXP.*>/

然后,我觉得在这里使用一些否定的课更安全,而且我的意思是[^>]+而不是.*

/<(?:VAC|ADJ)[^>]+>(.*)<EXP[^>]+>/

最后,您似乎不希望捕获中有<VAC<ADJ。所以我在(.*)部分添加了一个负向前瞻(并使(.*)懒惰):

/<(?:VAC|ADJ)[^>]+>((?:(?!<VAC|ADJ).)*?)<EXP[^>]+>/

eval.in updated

如果您希望获得<EXP部分(您的第一个示例),请扩展捕获组:

/<(?:VAC|ADJ)[^>]+>((?:(?!<VAC|ADJ).)*?<EXP[^>]+>)/

eval.in for this part

答案 1 :(得分:2)

几个问题:

  1. |表示“或”,但您没有使用任何类型的括号,因此它是<VAC或其他。您实际上想要<VACADJ,然后是其他人。

  2. .*贪婪。它尽可能匹配。如果您希望匹配较少,请使用.*?

  3. 正则表达式尝试尽快匹配。如果您希望以后匹配,请添加一个贪婪的.*

  4. 这应该有效:

    /.*<(?:VAC|ADJ).*?>(.*)<EXP.*>/