2011-02-05 593 views
2

我正在寫一個基本的分類工具,將採取一個標題,然後將其與一個關鍵字數組進行比較。例如: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

回答

4

這可以通過一個循環完成。

我會將糖果和糖果分成單獨的條目以提高效率。一個聰明的竅門是用一些標記替換匹配。我們用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"; 
2
$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

0

你n個執行O(N * M)查找是您的類別的大小和M爲標題的大小。你可以試試他們組織這樣的:

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

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

然後在標題的每個字,檢查$categories[$word]找到類別 - 這讓你O(M)。

1

提供的單詞數量並不太大,那麼創建一個反向查找表可能是一個想法,然後對它運行標題。

// 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

0

好這裏是我的新的答案,讓您在$貓[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);