数组中的任意项是否包含在字符串中?

4
我有一个关键字列表和一个黑名单。 我想删除所有包含任何黑名单项的关键字。 目前我是这样做的:
my @keywords = ( 'some good keyword', 'some other good keyword', 'some bad keyword');
my @blacklist = ( 'bad' );

A: for my $keyword ( @keywords ) {
    B: for my $bl ( @blacklist ) {
        next A if $keyword =~ /$bl/i;      # omitting $keyword
    }
    # some keyword cleaning (for instance: erasing non a-zA-Z0-9 characters, etc)
}

我想知道是否有更快的方法来处理这个问题,因为目前我有大约2500万个关键词和几百个黑名单词。


您想使用筛选过的 @keywords 创建一个新的数组吗? - mpapec
它可以是一个新数组。 - gib
3个回答

4
最简单的方法是将黑名单条目合并为一个正则表达式,然后在关键字列表中使用grep查找那些不符合该正则表达式的内容:
#!/usr/bin/env perl    

use strict;
use warnings;
use 5.010;

my @keywords = 
  ('some good keyword', 'some other good keyword', 'some bad keyword');
my @blacklist = ('bad');

my $re = join '|', @blacklist;
my @good = grep { $_ !~ /$re/ } @keywords;

say join "\n", @good;

输出:

some good keyword
some other good keyword

1
非常感谢!对于一个包含50k个关键词的测试,执行时间从34秒降至0.6秒。 - gib
1
https://metacpan.org/module/Regexp::Assemble - Regexp::Assemble 可以提高性能。 - Oesor
1
演示:perl -MData::Printer -MRegexp::Assemble -E "my $ra = Regexp::Assemble->new(); for my $word (qw/apple asp application aspire applicate aardvark snake/) { $ra->add($word) } p($ra->re);" 输出 (?:a(?:ppl(?:icat(?:ion|e)|e)|sp(?:ire)?|ardvark)|snake) - Oesor

3
预编译搜索可能有助于保留嵌套循环,例如my @blacklist = ( qr/bad/i )
或者,将my @blacklist = ('bad', 'awful', 'worst')更改为my $blacklist = qr/bad | awful | worst /;,然后用if($keywords[$i] =~ $blacklist) ...替换内部循环。

0

这应该可以:

my @indices;
for my $i (0..$#keywords) {
  for my $bl (@blacklist) {
    if ($keywords[$i] =~ $bl) {
      push(@indices, $i);
      last;
    }
  }
}
for my $i (@indices) {
  @keywords = splice(@keywords, $i);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接