PHP - самый быстрый способ найти несколько ключевых слов в тексте? - PullRequest
0 голосов
/ 01 февраля 2019

У меня большой массив ключевых слов (более тысячи), и мне нужно поискать в большом HTML-файле, чтобы найти, какие ключевые слова присутствуют в тексте.Затем мне нужно вернуть индексы этих ключевых слов, которые были найдены.

Например, если мой массив:

$keywords = array("love", "money", "minute", "loop"); // etc.

и если есть какие-либо экземпляры слов "деньги" и "цикл "Я хочу получить массив:

$results = array("1", "3"); // first $keyword element is 0

Я пытался использовать preg_match_all, но я не уверен, как получить $ совпадений, чтобы вернуть индексы моих ключевых слов.

Воткод, который у меня пока есть:

$keywords = array("love", "money", "minute", "loop");

$html = file_get_contents($url);

preg_match_all("#(love|money|minute|loop)#i", $html, $matches);

var_dump($matches);

Вот как выглядит результат:

array(2) {
  [0]=>
  array(4) {
    [0]=>
    string(6) "minute"
    [1]=>
    string(6) "minute"
    [2]=>
    string(5) "money"
    [3]=>
    string(5) "Money"
  }
  [1]=>
  array(4) {
    [0]=>
    string(6) "minute"
    [1]=>
    string(6) "minute"
    [2]=>
    string(5) "money"
    [3]=>
    string(5) "Money"
  }
}
  1. Какой самый быстрый / самый оптимальный способ сделать это в PHP?Preg_match_all хорошо?Я хочу избежать использования foreach, так как моя функция будет сканировать весь HTML более тысячи раз (не очень эффективно по времени).

  2. Как получить индексы моих ключевых слов?Например, были найдены ключевые слова с номерами 0 и 3, независимо от их количества.

Ответы [ 4 ]

0 голосов
/ 01 февраля 2019

Если вам просто нужно увидеть, какое из ключевых слов присутствует в тексте, вы можете сопоставить stripos с массивом ключевых слов.

$result = array_map(function ($keyword) use (&$html) {
    return stripos($html, $keyword) !== false;
}, $keywords);

Теперь stripos просто найдетодна строка в другой.В нем нет понятия слов, и если вы не хотите сопоставлять ключевые слова, если они существуют как часть более длинного слова, вам нужно использовать регулярное выражение с границами слов.Но выражение, которое вы используете в данный момент, этого не делает, так что это может не быть проблемой.

0 голосов
/ 01 февраля 2019

Просто альтернатива, использующая str_word_count(), которую вы не видите много, используя 2 в качестве второго параметра, чтобы разбить строку на слова в массиве с начальной позицией в качестве ключа.Затем используйте array_intersect(), чтобы сопоставить это с ключевыми словами ...

$keywords = array("love", "money", "minute", "loop");
// string courtesy of Joni's answer
$html = "love and money make the world loop around in a loop three times per minute";
$words = str_word_count($html, 2);
$match = array_intersect($words, $keywords);
print_r($match);

дает ...

Array
(
    [0] => love
    [9] => money
    [30] => loop
    [47] => loop
    [68] => minute
)

Не уверен, как это работает с любым регулярным выражением, просто попробуйтеих.

Или, если не считать места на экране ...

print_r(array_intersect(str_word_count($html, 2), $keywords));

Если вы просто хотите, чтобы ключевое слово присутствовало, просто измените порядок массивов в array_intersect() (и caseнечувствителен - сначала преобразуйте в нижний регистр, используя strtolower()) ...

$match = array_intersect($keywords, str_word_count(strtolower($html), 1));

, что дает ...

Array
(
    [0] => love
    [1] => money
    [2] => minute
    [3] => loop
)

Последнее обновление:

Просмотр производительностиМое решение можно оптимизировать, перевернув массивы так, чтобы вместо сканирования каждого массива на предмет строкового значения проверка наличия ключа была намного быстрее ...

$match = array_flip(array_intersect_key(array_flip($keywords), array_flip(str_word_count(strtolower($html), 1))));
0 голосов
/ 01 февраля 2019
$keywords = array("love", "money", "minute", "loop");

// The function "GetHtmlWords" gets the html content and clean it from spacial 
// characters
$htmlWordsArray = explode(' ', GetHtmlWords($url));

// Calculate the intersection - intersect return values while preserving keys
// use array_keys to get just the keys. double check if first index is 0 or 1
$result = array_keys(array_intersect($keywords, $htmlWordsArray));

var_dump($result);

// Get the content of the html, cleaned from spacial characters, with space 
// between words
function GetHtmlWords($url) {
  $htmlContent = file_get_contents($url);

  // Handle , and . that may split between words, without space.
  // for example hi.there first,second
  $html = $str_replace([".",","], " ", $htmlContent);

  // Clean the text from spacial characters (including , and .)
  $cleanHtml = preg_replace('/[^A-Za-z0-9\- ]/', '', $html)

  // Remove duplicate spaces
  $htmlWordsOnly = $str_replace("  ", " ", $html);

  return($htmlWordsOnly);
}
0 голосов
/ 01 февраля 2019

Вы можете использовать флаг PREG_OFFSET_CAPTURE, чтобы получить смещения:

$matches=[];
$html = "love and money make the world loop around in a loop three times per minute";
preg_match_all("#love|money|minute|loop#i", $html, $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $m) echo $m[0]." found at index ".$m[1]."\n";

// output:
love found at index 0
money found at index 9
loop found at index 30
loop found at index 47
minute found at index 68

Теперь, это выполняет достаточно быстро , чтобы вы могли оценить.Если это произойдет, нет смысла искать более сложные альтернативы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...