PHP Stripos не возвращает все позиции

Я возвращаю весь массив, где функция stripos соответствует этому

$requestedservice = request('service');
$result_array = array_filter($allservicesname, function($item) use ($requestedservice) {
return (stripos($item, $requestedservice) !== false);
        });

Это работает только для первого случая, например, если стог сена равен Walk dance and rock, если игла равна Walk, она возвращает Walk dance and rock, но если игла равна Walk rock, она не возвращает Walk dance and rock. Почему это происходит?

Есть ли способ найти для всех вхождений, чтобы он соответствовал стогу сена Walk dance and rock с иголкой Walk rock?

А также, если игла Walk run, она не должна соответствовать Walk dance and rock, это нормальный вариант использования.


person Cowgirl    schedule 03.12.2017    source источник
comment
Все работает как положено. Вам нужно будет вызвать отдельный stripos() для каждого слова, которое может или не может быть разделено другими словами/символами. Возможно, вы захотите использовать регулярное выражение, такое как preg_grep()   -  person mickmackusa    schedule 03.12.2017
comment
Как говорит php man: stripos — Найти позицию первого вхождения в строку подстроки без учета регистра. Таким образом, вы не можете найти несколько вхождений с помощью этой функции. Игольчатый рок. не является подстрокой танцевального рока Walk, поскольку @micmackusa говорит, что вам, вероятно, нужно использовать регулярное выражение   -  person Riccardo    schedule 03.12.2017
comment
@Riccardo Любое другое решение, чтобы поставить walk rock в walk dance rock   -  person Cowgirl    schedule 03.12.2017
comment
php.net/manual/it/function.preg-match.php это должно работать   -  person Riccardo    schedule 03.12.2017


Ответы (2)


Похоже, вы сможете добиться желаемой фильтрации с помощью цикла проверки ключевых слов без учета регистра.

Код: (демонстрация)

$allservicesname=['dance','Walk rock','Walk dance and rock','Walk'];  // array of haystacks

$requestedservice='walk rock';  // string of needles

$result_array=array_filter($allservicesname,function($string)use($requestedservice){
    foreach(explode(' ',$requestedservice) as $keyword){
        if(stripos($string,$keyword)===false){
            return false;
        }
    }
    return true;
});

var_export($result_array);

Выход:

array (
  1 => 'Walk rock',
  2 => 'Walk dance and rock',
)

Обратите внимание, что исходные ключи сохраняются в выходном массиве. Кроме того, я должен отметить, что ключевые слова могут появляться в любом порядке и сохранять точность.


В качестве альтернативы, если вас не пугает идея регулярных выражений, preg_grep() может сжато выполнить эту задачу. Это функция, предназначенная для фильтрации массивов с использованием регулярных выражений для каждого элемента.

Код: (Демо) (Демонстрация шаблона регулярных выражений)

$allservicesname=['Walk dance and rock walk','dance','walk','rock and walk','sidewalk and rockwall'];  // array of haystacks

$requestedservice='walk rock';  // string of needles
$pattern='/(?=.*\Q'.str_replace(' ','\E)(?=.*\Q',$requestedservice).'\E)/i';  // with literal substring matching, no wordboundaries
//$pattern='/(?=.*\b\Q'.str_replace(' ','\E\b)(?=.*\b\Q',$requestedservice).'\E\b)/i';  // with wordboundaries  
echo $pattern,"\n";

$result_array=preg_grep($pattern,$allservicesname);

var_export($result_array);

Выход:

/(?=.*\Qwalk\E)(?=.*\Qrock\E)/i
array (
  0 => 'Walk dance and rock walk',
  3 => 'rock and walk',
  4 => 'sidewalk and rockwall',
)

Если вы не хотите, чтобы элемент [4] квалифицировался, тогда необходимы границы слов - вместо этого используйте второе (закомментированное) объявление шаблона.

\Q..\E гарантирует, что никакие символы со специальным значением в регулярном выражении не могут помешать выполнению. Подстроки внутри них интерпретируются «буквально».

person mickmackusa    schedule 03.12.2017
comment
Пожалуйста, объясните, как это возможно, потому что мои демонстрационные ссылки доказывают их успех. Можете ли вы отправить мне демо-ссылку с примерами данных, которые нарушают мои методы? Я исправлю это. - person mickmackusa; 04.12.2017
comment
Спасибо. Это работает для меня. Но единственная проблема, с которой я столкнулся, заключается в том, что он не соответствует специальному символу, такому как & или ', как я могу сопоставить их? - person Cowgirl; 06.12.2017
comment
Мы говорим об ошибках сопоставления при обработке html-объектов (",',&,<,>)? Похоже на работу для php.net/manual/en/function.html -entity-decode.php Если это не решит вашу проблему, пришлите мне демо-ссылку (как я включил в свой ответ), которая воспроизводит проблему, и я ее изучу. - person mickmackusa; 06.12.2017
comment
Он соответствует walk - rock с walk rock, но не соответствует walk - rock с walk - rock Я также пытался использовать htmlentitydecode, в чем может быть проблема - person Cowgirl; 07.12.2017
comment
Пожалуйста, дайте мне ваш точный код в демо-ссылке, и я исправлю его. - person mickmackusa; 07.12.2017
comment
Есть несколько символов, похожих на дефис. Если это икота, убедитесь, что дефис является правильным дефисом. Если вы хотите искать только по словам в строке поиска, str_word_count () может быть простым обходным решением для моего первого метода. - person mickmackusa; 07.12.2017
comment
/(?=.*\b\Q'.str_replace(' ','\E\b)(?=.*\b\Q',$requestedservice).'\E\b)/i'На самом деле я использую это, я не смог воспроизвести эту проблему на тестере регулярных выражений. - person Cowgirl; 07.12.2017
comment
Я не могу вам помочь без дополнительной информации. Мои методы должны работать, потому что демонстрации доказывают их правильность. Я рад помочь, если вы можете дать мне больше, чтобы идти дальше. - person mickmackusa; 07.12.2017

Как уже упоминалось, stripos возвращает только первое вхождение. После преобразования строки в массив с помощью explode вы можете использовать < цикл href="http://php.net/manual/en/control-structures.foreach.php" rel="nofollow noreferrer">foreach с in_array, чтобы выполнить то, что вы ищете.

Вот это действие:

$all_services = explode(" ", "walk dance and rock");
$requested_services = explode(" ", "walk rock");
$result_array = array();

foreach ($all_services as $service) {
    if (in_array($service, $requested_services)) {
        $result_array[] = $service;
    }
}
person vqdave    schedule 03.12.2017