以这两个文本为例
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
这样做的正确方法是什么?
答案 0 :(得分:5)
首先你的OR运算符的范围是错误的:
/<VAC|<ADJ.*>(.*)<EXP.*>/
这将匹配<VAC
或<ADJ.*>(.*)<EXP.*>
。将所需部分包裹在非捕获组周围:
/<(?:VAC|ADJ).*>(.*)<EXP.*>/
然后,我觉得在这里使用一些否定的课更安全,而且我的意思是[^>]+
而不是.*
:
/<(?:VAC|ADJ)[^>]+>(.*)<EXP[^>]+>/
最后,您似乎不希望捕获中有<VAC
或<ADJ
。所以我在(.*)
部分添加了一个负向前瞻(并使(.*)
懒惰):
/<(?:VAC|ADJ)[^>]+>((?:(?!<VAC|ADJ).)*?)<EXP[^>]+>/
如果您希望获得<EXP
部分(您的第一个示例),请扩展捕获组:
/<(?:VAC|ADJ)[^>]+>((?:(?!<VAC|ADJ).)*?<EXP[^>]+>)/
答案 1 :(得分:2)
几个问题:
|
表示“或”,但您没有使用任何类型的括号,因此它是<VAC
或其他。您实际上想要<VAC
或ADJ
,然后是其他人。
.*
贪婪。它尽可能匹配。如果您希望匹配较少,请使用.*?
。
正则表达式尝试尽快匹配。如果您希望以后匹配,请添加一个贪婪的.*
。
这应该有效:
/.*<(?:VAC|ADJ).*?>(.*)<EXP.*>/