PHP中获取关键字列表并将其与所有字词的搜索结果(如标题数组)匹配的最快方法是什么?
例如,如果我的关键字词组是“优秀皮鞋”,则以下标题将匹配...
...虽然这些不会匹配:
我想有一些关于数组函数或RegEx(正则表达式)的技巧可以快速实现这一点。
答案 0 :(得分:4)
我会使用标题中单词的索引并测试每个搜索词是否在该索引中:
$terms = explode(' ', 'great leather shoes');
$titles = array(
'Get Some Really Great Leather Shoes',
'Leather Shoes Are Great',
'Great Day! Those Are Some Cool Leather Shoes!',
'Shoes, Made of Leather, Can Be Great'
);
foreach ($titles as $title) {
// extract words in lowercase and use them as key for the word index
$wordIndex = array_flip(preg_split('/\P{L}+/u', mb_strtolower($title), -1, PREG_SPLIT_NO_EMPTY));
// look up if every search term is in the index
foreach ($terms as $term) {
if (!isset($wordIndex[$term])) {
// if one is missing, continue with the outer foreach
continue 2;
}
}
// echo matched title
echo "match: $title";
}
答案 1 :(得分:3)
你可以像
那样preg_grep()你的数组 /^(?=.*?\bgreat)(?=.*?\bleather)(?=.*?\shoes)/
或(可能更快)分别grep每个单词然后array_intersect结果
答案 2 :(得分:2)
这可能是一个非常天真的解决方案(很可能有更高效/优雅的解决方案),但我可能会做类似以下的事情:
$keywords = array(
'great',
'leather',
'shoes'
);
$titles = array(
'Get Some Really Great Leather Shoes',
'Leather Shoes Are Great',
'Great Day! Those Are Some Cool Leather Shoes!',
'Shoes, Made of Leather, Can Be Great',
'Leather Shoes on Sale Today!',
'You\'ll Love These Leather Shoes Greatly',
'Great Shoes Don\'t Come Cheap'
);
$matches = array();
foreach( $titles as $title )
{
$wordsInTitle = preg_split( '~\b(\W+\b)?~', $title, null, PREG_SPLIT_NO_EMPTY );
if( array_uintersect( $keywords, $wordsInTitle, 'strcasecmp' ) == $keywords )
{
// we have a match
$matches[] = $title;
}
}
var_dump( $matches );
不知道这个基准如何。
答案 3 :(得分:1)
我无法为您提供明确的答案,但我会尝试对每个建议的解决方案进行基准测试,并将首先将一些in_array链接在一起。
if (in_array('great', $list) && in_array('leather', $list) && in_array('shoes', $list)) {
// Do something
}
答案 4 :(得分:1)
您可以使用
/(?=.*?\great\b)(?=.*?\bshoes\b)(?=.*?\bleather\b)/
注意几件事
a)你需要两端的单词边界,否则你最终可能会找到包含你正在寻找的单词的单词,例如“皮革鞋带来伟大”。
b)我使用懒惰的通配符匹配(即*?)。这提高了效率,因为默认情况下*是贪婪的(即它消耗尽可能多的字符,并且只有它们才有利于整体匹配)。因此,如果我们没有尾随?,。*将匹配该行中的所有内容,然后回溯以匹配'great'。然后对“鞋子”和“皮革”重复相同的程序。通过*懒惰,我们避免这些不必要的回溯。
答案 5 :(得分:1)
我不知道绝对最快的方式,但这可能是使用正则表达式执行此操作的最快方法:
'#(?:\b(?>great\b()|leather\b()|shoes\b()|\w++\b)\W*+)++\1\2\3#i'
这匹配字符串中的每个单词,如果单词恰好是您的关键字之一,则空捕获组“将其检查”。一旦匹配了字符串中的所有单词,后引用(\1\2\3
)就会确保至少看过三个关键字中的每一个。
通常建议用于此类任务的基于前瞻性的方法需要多次扫描整个字符串 - 每个关键字一次。这个正则表达式只需要扫描一次字符串 - 实际上,占有量词(++
,*+
)和原子组((?>...)
)禁用了回溯。
那就是说,除非我知道它造成了瓶颈,否则我仍会采用先行方法。在大多数情况下,其更高的可读性值得在性能上进行权衡。