优化正则表达式匹配m:n列表(针对多个列表的多个单词列表)

时间:2013-08-18 09:49:26

标签: regex perl

我有大字列表,看起来像这样(这个数据来自db):

[
    {
        keyword => 'bmw.*red.*1999',
        owner => 'someone'
        #... other attributes
    },
    {
        keyword => 'toyota.*black.*1999',
        owner => 'someone else'
        #... other attributes
    },
    # and so on ... up to 300 different keywords in a list
]

我必须经常将“关键字”与其他许多列表进行匹配。因为每次我将“keyword”编译为regexp时都会使用此关键字列表:

map { $_->{_compiled} = qr/$_->{keyword}/i } @keywords;

并将每个关键字与其他列表中的每个元素进行比较:

foreach my $other in (@other) {
    foreach my $keword (@keywords) {
        if ($other->{name} =~ $keyword->{_compiled}) {
              ## do something with $other and $keyword
        }
    }
}

这些操作应该每10分钟运行一次,应该有大约50个关键字列表(最多300个元素)和50个其他列表,这些列表将根据这些关键字进行检查。它应该会增长。

我想尽可能优化匹配速度,我有两个想法/问题:

  • 将已编译的regexp($ keyword-> {_ compiled})保存在数据库中供以后使用,但我不确定这有多大帮助(我没有做任何基准测试)

  • 将所有“关键字”或“_compiled”加入一个大正则表达式并一步比较所有内容。

代码:

my @compiled = grep { $_->{_compiled} } @keywords;

# or is this better?
my $rx = "(".(join "|", grep { $_->{keyword} } @keywords).")";
my $compiled = qr/$rx/i;

foreach my $other in (@other) {
   if ($other->{name} =~ @compiled) {
       ## do something with $other and $keyword
       ## 
       ## but now there is no way to get "owner" of matched keyword

   }
}

我的“问题”是我必须能够使用匹配关键字的“所有者”和其他属性。如果我在一个大正则表达式中加入所有内容或将_compiled放在一个数组中,我就无法匹配

regexp是否有“最佳解决方案” - 将大型列表与大型列表进行比较?我甚至不确定我是否应该担心性能问题,但是列表会增长,我希望做好准备。

1 个答案:

答案 0 :(得分:1)

您可以尝试将bmw.*red.*1999更改为

\bbmw\b(?>[^r]++|\Br|r(?!ed))++\bred\b(?>[^1]++|\B1|1(?!999))++\b1999\b

并且所有关键字都相同。这种改变的目标是尽可能快地失败。

请注意,转换可以通过2次连续搜索/替换自动完成(它总是相同的)

search: (\w+)
replace: \b$1\b

search: \.\*(?=\\b(\w)(\w+)\\b)
replace: (?>[^$1]++|\B$1|$1(?!$2\b))++

第二个关键字

的示例
toyota.*black.*1999
first replace:
\btoyota\b.*\bblack\b.*\b1999\b
second replace:
\btoyota\b(?>[^b]++|\Bb|b(?!lack\b))++\bblack\b(?>[^1]++|\B1|1(?!999\b))++\b1999\b

然后将编译后的表达式存储在数据库中。

相关问题