PHP - найти часть строки в многомерном массиве со списком слов

Coool6 спросил: 28 апреля 2018 в 08:20 в: php

Извините, что беспокою вас, я потратил много времени на StackOverflow, ища решение, но это всегда другой вопрос.

Вот моя проблема:

$array = array (
 "1" => array("fruit","salad","vegetable"),
 "2" => array("beef","meat","sausage"),
 "3" => array("chocolate","cake","bread")
);$sentence = "I love big sausage"; // if it can work  with sausageS it's even better

Мне нужно связать предложение с категорией, поэтому мне нужно проанализировать предложение и вернуть идентификатор подмассива, соответствующий предложению. Например, "2" в моем примере.

Я ищу решение с лучшей производительностью (поэтому я бы хотел избежать нескольких foreach / while / for). Но я предполагаю, что у меня нет другого выбора, кроме как "взорвать" предложение и "зайти" по крайней мере.

В проекте используется PHP7, и если он сможет использовать удивительные родные функции, это будет здорово.

Массив может быть отформатирован следующим образом, если его легче обрабатывать:

$array = array (
 "1" => array("id" => "1", "words" => "fruit,salad,vegetable"),
 "2" => array("id" => "2", "words" => "beef,meat,sausage"),
 "3" => array("id" => "3", "words" => "chocolate,cake,bread")
);

Спасибо большое! & Lt; 3


3 ответа

Andreas ответил: 28 апреля 2018 в 08:45

Я думаю, что это лучшее, что я могу сделать.

Перед массивом и используйте preg_grep для поиска совпадений.
Я использую str_replace для замены пробелов с помощью | который используется как "или" в регулярном выражении.

foreach($array as $key => $sub){
    if(preg_grep("/" . str_replace(" ", "|", $sentence) . "/" ,$sub )){
        echo "Match in ". $key . "\n";
    }
}

https://3v4l.org/BqkW2


Чтобы соответствовать вашему примеру sussageS, вы можете отменить поиск и добавьте .*? в grep.
$arrSent = explode(" ", $sentence);
foreach($array as $key => $sub){
    if(preg_grep("/" . implode(".*?|", $sub) . ".*?/" , $arrSent))    
    {
        echo "Match in ". $key . "\n";
    }
}

https://3v4l.org/MJqrv

Но это также примет sussage_and_beans. Если вы хотите только совместить слово во множественном числе (в конце добавлен s). Измените .*? на s.
Но он будет чувствителен к регистру, поэтому sussageS, как в вашем примере, не будет работать.
но с помощью: if(preg_grep("/" . implode("s|", $sub) . "s/i" , $arrSent)) Должно сделать регистр нечувствительным.

Coool6 ответил: 28 апреля 2018 в 03:09
Большое спасибо! Второе решение работает очень хорошо и с одним циклом! Удивительно. Первое решение, похоже, возвращает любой результат, который содержит часть слова в предложении. Например, если у вас есть "bigmac" в первом массиве, скрипт вернет вам идентификатор 1 & 2 из-за "большого" в предложении. Я думал, что это будет противоположная причина, потому что второй скрипт выглядит более разрешительным, чем первый. Но в любом случае большое спасибо за то, что вы сделали, вы потрясающий < 3
Coool6 ответил: 28 апреля 2018 в 03:19
Но просто вопрос: как сделать второй скрипт нечувствительным? Причина, по которой я пытался заменить на "if (preg_grep (" / ". Implode (" s | ", $ sub)." S / i ", $ arrSent)", и он не работает, скрипт ничего не возвращает.
Andreas ответил: 28 апреля 2018 в 03:46
Он работает для меня, не уверен, почему он не работает для вас. 3v4l.org/OE1uN
Coool6 ответил: 01 мая 2018 в 06:35
Большое спасибо ! Это интересный способ без петли! Это потрясающе. Не знал, что я могу так поступить! Еще раз спасибо !
The fourth bird ответил: 28 апреля 2018 в 01:14

Если вы взорвите свой $sentence и используете пробел в качестве разделителя, вы получите массив слов.

Вы можете использовать array_filter для удаления этих массивов из $array, проверив, содержит ли пересечение 1 или более слов, используя array_intersect.

Затем вы можете вернуть массив с помощью array_keys, чтобы получить все идентификаторы, содержащие слова (слова), которые содержатся в вашем предложении.

$array = array (
    "1" => array("fruit","salad","vegetable"),
    "2" => array("beef","meat","sausage"),
    "3" => array("chocolate","cake","bread")
);$expl = explode(' ', "I love big sausage");
$array = array_filter($array, function($x) use ($expl) {
    return count(array_intersect($expl, $x)) > 0;
});
var_dump(array_keys($array));

Демо

Это даст вам:

array(1) {
  [0]=>
  int(2)
}