为什么Regexp :: Assemble失败了这些简单的regexp?

时间:2009-11-15 23:31:04

标签: regex perl

我在我的项目中使用Regexp::Assemble,但我不明白为什么这个小样本不起作用:

#!/usr/bin/perl

use strict;
use warnings;

use Regexp::Assemble;

my $re1 = "(run (?:pre|post)flight script for .+)";
my $re2 = "((?:Configu|Prepa)ring volume .+)";

my $ra   = Regexp::Assemble->new;
$ra->add($re1);
$ra->add($re2);
my $global = $ra->re;

print "GLOBAL: $global\n";

1;

我收到了这个错误:

Unmatched ( in regex; marked by <-- HERE in m/( <-- HERE ?:(run (?:pre|post)flight script for|((?:Configu|Prepa)ring volume) .+)/ at /usr/share/perl5/Regexp/Assemble.pm line 1003.

修改 如果我只打印生成的Regexp($ ra-&gt; as_string),我得到了这个:

GLOBAL: (?:(run (?:pre|post)flight script for|((?:Configu|Prepa)ring volume) .+)

有一个')'缺失...

3 个答案:

答案 0 :(得分:4)

Ether的方法似乎是一个计划 - 如果你看一下模块文档,它会特别提到要注意:

add() ... 它使用一个朴素的正则表达式来表示可能被复杂表达式欺骗的字符串(具体来说,它将无法使用嵌套的括号表达式,例如ab(cd( ef)?gh)ij正确)。如果是这种情况,字符串的末尾将不会被正确标记并作为一个长字符串返回。

答案 1 :(得分:4)

我是R :: A的作者。这个问题每隔几年出现一次。这个想法是你不想添加复杂的父母模式。添加更多,更简单的模式,例如

run preflight script for .+
run postflight script for .+
Configuring volume .+
Preparing volume .+

不要尝试完成模块的工作。例如,你的过早分组导致了所有模式的共同尾随.+,这些模式没有被计算在正则表达式中的一个出现中。结果是你引入了不必要的回溯。你添加的模式越多,它就越糟糕。

以不同的顺序调用add()将产生相同的结果模式(否则这是我想知道的错误)。

否则你可以自己预先说明模式,并使用insert()将模式lexemes直接插入到用于构建模式的内部trie结构中。 (这会更快,因为词法分析器非常慢:它消耗的时间超过组装模式的运行时间的一半)。

答案 2 :(得分:2)

这看起来像个bug?您正在混淆正则表达式构造函数。看看它如何结合你的两种模式并使括号不匹配:

my $re1 =     "(run (?:pre|post)flight script for .+)";
my $re2 =                                        "((?:Configu|Prepa)ring volume .+)";

#         m/(?:(run (?:pre|post)flight script for|((?:Configu|Prepa)ring volume) .+)/ at...

尝试从正则表达式中删除一组额外的括号,看看是否有帮助:

my $re1 = "run (?:pre|post)flight script for .+";
my $re2 = "(?:Configu|Prepa)ring volume .+";