3 Stimmen

php match string zu mehreren Arrays von Schlüsselwörtern

Ich schreibe ein einfaches Kategorisierungstool, das einen Titel mit einer Reihe von Schlüsselwörtern vergleicht. Beispiel:

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

Gibt es kreative Möglichkeiten, diese Kategorien in einer Schleife zu durchlaufen oder zu sehen, welche Kategorie die meisten Treffer hat? Beachten Sie, dass ich im Array "dining" eine Regex habe, um Variationen des Wortes "candy" zu finden. Ich habe Folgendes ausprobiert, aber da die Kategorielisten ziemlich lang sind, frage ich mich, ob dies der beste Weg ist:

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

Danke! Steve

EDIT: Dank @jmathai konnte ich die Rangliste hinzufügen:

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

4voto

jmathai Punkte 453

Dies kann mit einer einzigen Schleife geschehen.

Ich würde Süßigkeiten und Bonbons aus Gründen der Effizienz in separate Einträge aufteilen. Ein cleverer Trick wäre, Streichhölzer durch ein Token zu ersetzen. Nehmen wir 10 #'s.

$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";

2voto

Crayon Violent Punkte 31424
$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);

1voto

Orbling Punkte 20005

Wenn die Anzahl der Wörter nicht zu groß ist, könnte es eine gute Idee sein, eine Reverse-Lookup-Tabelle zu erstellen und dann den Titel mit dieser Tabelle abzugleichen.

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

0voto

Fragsworth Punkte 31001

Sie führen eine O(n*m)-Suche durch, wobei n die Größe Ihrer Kategorien und m die Größe eines Titels ist. Sie könnten versuchen, sie wie folgt zu organisieren:

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

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

Prüfen Sie dann für jedes Wort in einem Titel $categories[$word] um die Kategorie zu finden - so erhalten Sie O(m).

0voto

Crayon Violent Punkte 31424

Okay hier ist meine neue Antwort, die Sie Regex in $cat[n] Werte verwenden können ... es gibt nur eine Einschränkung über diesen Code, die ich nicht herausfinden kann ... aus irgendeinem Grund, es schlägt fehl, wenn Sie jede Art von metacharacter oder Zeichenklasse am Anfang Ihrer $cat[n] Wert haben.

Beispiel: .*food wird nicht funktionieren. Aber s.afood o sea.* usw... oder Ihr Beispiel von cand(y|ies) wird funktionieren. Ich dachte eigentlich, dass dies für Sie ausreichen würde, da ich davon ausging, dass der Sinn der Regex darin besteht, verschiedene Zeitformen von Wörtern zu behandeln, und die Wortanfänge ändern sich in diesem Fall selten.

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);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X