1

以这两个文本为例

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.";

我想要做的是提取所有以<VACor为界的字符串,<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

正确的方法是什么?

4

2 回答 2

5

首先,您的 OR 运算符的范围错误:

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

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

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

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

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

最后,您似乎不想要任何<VAC<ADJ在捕获中。因此,我在该部分中添加了一个否定的前瞻(并使之变得(.*)懒惰)(.*)

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

eval.in 更新

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

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

这部分的 eval.in

于 2013-09-26T07:41:35.993 回答
2

几个问题:

  1. |意思是“或”,但你没有使用任何类型的括号,所以它是<VAC或其余的。您实际上想要<VACor ADJ,然后是其余的。

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

  3. 正则表达式尝试尽快匹配。如果您希望它稍后匹配,请在前面加上一个 greedy .*

这应该有效:

/.*<(?:VAC|ADJ).*?>(.*)<EXP.*>/
于 2013-09-26T07:42:04.960 回答