PHP匹配字符串到多个关键字数组

问题描述:

我正在写一个基本的分类工具,将采取一个标题,然后将其与一个关键字数组进行比较。例如:PHP匹配字符串到多个关键字数组

$cat['dining'] = array('food','restaurant','brunch','meal','cand(y|ies)'); 
$cat['services'] = array('service','cleaners','framing','printing'); 
$string = 'Dinner at seafood restaurant'; 

是否有创造性的方法来循环这些类别或查看哪些类别具有最匹配的?请注意,在“餐饮”数组中,我使用正则表达式来匹配单词candy的变体。我尝试以下,但这些类别名单越来越长的很漂亮,我想知道如果这是最好的方法:

$keywordRegex = implode("|",$cat['dining']); 
preg_match_all("/(\b{$keywordRegex}\b)/i",$string,$matches]); 

谢谢你,史蒂夫

编辑: 感谢@jmathai,我是能够添加排名:

$matches = array(); 
    foreach($keywords as $k => $v) { 
     str_replace($v, '#####', $masterString,$count); 
     if($count > 0){ 
      $matches[$k] = $count; 
     } 
    } 
    arsort($matches); 
+0

不知道PHP太好,但我怀疑哈希会比正则表达式更快。如果你有一个值作为一个实际的正则表达式(如cand(y | ies))作为正则表达式运行它,例如把正则表达式值放入一个单独的散列表中。 – sln 2011-02-05 02:04:46

这可以通过一个循环完成。

我会将糖果和糖果分成单独的条目以提高效率。一个聪明的窍门是用一些标记替换匹配。我们用10#。

$cat['dining'] = array('food','restaurant','brunch','meal','candy','candies'); 
$cat['services'] = array('service','cleaners','framing','printing'); 
$string = 'Dinner at seafood restaurant'; 

$max = array(null, 0); // category, occurences 
foreach($cat as $k => $v) { 
    $replaced = str_replace($v, '##########', $string); 
    preg_match_all('/##########/i', $replaced, $matches); 
    if(count($matches[0]) > $max[1]) { 
    $max[0] = $k; 
    $max[1] = count($matches[0]); 
    } 
} 

echo "Category {$max[0]} has the most ({$max[1]}) matches.\n"; 

$cat['dining'] = array('food','restaurant','brunch','meal'); 
$cat['services'] = array('service','cleaners','framing','printing'); 
$string = 'Dinner at seafood restaurant'; 

$string = explode(' ',$string); 
foreach ($cat as $key => $val) { 
    $kwdMatches[$key] = count(array_intersect($string,$val)); 
} 
arsort($kwdMatches); 

echo "<pre>"; 
print_r($kwdMatches); 
+0

这不包含正则表达式? – 2011-02-05 01:05:14

+0

嗯...这不包括通配符/变体匹配... – 2011-02-05 01:07:49

你n个执行O(N * M)查找是您的类别的大小和M为标题的大小。你可以试试他们组织这样的:

const $DINING = 0; 
const $SERVICES = 1; 

$categories = array(
    "food" => $DINING, 
    "restaurant" => $DINING, 
    "service" => $SERVICES, 
); 

然后在标题的每个字,检查$categories[$word]找到类别 - 这让你O(M)。

提供的单词数量并不太大,那么创建一个反向查找表可能是一个想法,然后对它运行标题。

// One-time reverse category creation 
$reverseCat = array();  
foreach ($cat as $cCategory => $cWordList) { 
    foreach ($cWordList as $cWord) { 
     if (!array_key_exists($cWord, $reverseCat)) { 
      $reverseCat[$cWord] = array($cCategory); 
     } else if (!in_array($cCategory, $reverseCat[$cWord])) { 
      $reverseCat[$cWord][] = $cCategory; 
     } 
    } 
} 

// Processing a title 
$stringWords = preg_split("/\b/", $string); 

$matchingCategories = array(); 
foreach ($stringWords as $cWord) { 
    if (array_key_exists($cWord, $reverseCat)) { 
     $matchingCategories = array_merge($matchingCategories, $reverseCat[$cWord]); 
    } 
} 

$matchingCategories = array_unique($matchingCategories); 
+0

请注意,如果需要排名,那么不要在末尾使用`array_unique()`调用,而是使用`$ matchingCategories`来构建一个计数表,然后是一个`arsort()`将给出下降的排名。 – Orbling 2011-02-05 01:20:42

好这里是我的新的答案,让您在$猫[N]值......只有一个关于这个代码,我想不通......出于某种原因需要注意的,它失败使用正则表达式如果您在$ cat [n]值的开头有任何类型的元字符或字符类。

例如:.*food不起作用。但是s.afoodsea.*等...或者您的cand(y|ies)的示例将工作。我认为这对你来说足够好,因为我认为正则表达式的意义在于处理不同时态的单词,并且在这种情况下单词的开头几乎不会改变。

function rMatch ($a,$b) { 
    if (preg_match('~^'.$b.'$~i',$a)) return 0; 
    if ($a>$b) return 1; 
    return -1; 
} 

$string = explode(' ',$string); 
foreach ($cat as $key => $val) { 
    $kwdMatches[$key] = count(array_uintersect($string,$val,'rMatch')); 
} 
arsort($kwdMatches); 

echo "<pre>"; 
print_r($kwdMatches);