在PHP中,匹配一个字符串与关键字列表的最有效方法是什么?

3

我有一个关键词列表,需要检查其中是否有任何一个出现在字符串中。例如:

/* Keywords */
Rock
Paper
Scissors

/* Strings */
"This town rocks!"    /* Match */
"Paper is patient"    /* Match */
"Hello, world!"       /* No match */

我可以将关键字放入数组中,循环遍历并在每次迭代中使用preg_match()或substr()函数,但这似乎有点消耗CPU。我已经尝试过正则表达式,但没有太大的成功。

在编写代码时,最高效的方法(就代码量和CPU负载而言)是什么?

请注意,比较必须不区分大小写。


1
使用正则表达式字典树 (?i)(?:rock|paper|scissors)。第一层字典树是 [psr]。如果你有大量的关键词(比如几千个),可以使用工具将它们转换成多级字典树。http://www.regexformat.com - user557597
你说“那似乎有点CPU昂贵”,但你试过它们中的任何一个吗?如果你想知道事情需要多长时间,那么最好的方法就是实际尝试。你也可以使用像xdebug这样的软件包:http://xdebug.org/ - Andy Lester
3个回答

3

使用包含所有可能的正则表达式,可以确保字符串只被扫描一次,而不是针对N个关键词进行N次扫描。PCRE库非常优化。

preg_match('/rock|paper|scissors/i', $string);

如果您的关键字具有共同前缀并且您利用了这一点(基本上通过构建Trie并将其内联),则速度会更快。
preg_match('/rock|paper|sci(?:ssors|ence)/i', $string);

最后还有一个问题需要解决。
preg_grep($regex, $array_of_strings);

这将会匹配一个字符串数组并返回匹配的结果。


1

为了查看是否存在任何关键词,您可以使用关键词数组来执行此操作:

if(str_ireplace($keyword_array, '', $string) != $string) {
    //match
} else {
    //no match
}

str_ireplace会为N个关键字扫描字符串N次,并为新字符串分配内存。在性能方面相当糟糕。 - Kornel

0
如果你事先不知道你的关键词,并且你有多个字符串需要搜索,你可以将关键词合并成一个正则表达式,然后用grep命令来搜索这些字符串。
$keywords = array ('Rock', 'Paper', 'sciSSors');
$strings  = array (
    "This town rocks!",
    "Hello, world!",
    "Paper is patient",
);

$rc = preg_grep(
    sprintf('/%s/i', implode('|', array_map('preg_quote', $keywords))),
    $strings
);

/**
array(2) {
  [0]=>
  string(16) "This town rocks!"
  [2]=>
  string(16) "Paper is patient"
}
*/

在这里查看。


这并不是完全可靠的:如果您的关键字包含“/”,则无法得到您期望的结果。留给读者作为练习。 - bishop

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