strpos () с несколькими иглами?

Я ищу функцию типа strpos () с двумя существенными отличиями:

  1. Уметь принимать несколько игл. Я имею в виду тысячи игл на них.
  2. Поиск всех вхождений игл в стоге сена и возврат массива начальных позиций.

Конечно, это должно быть эффективным решением, а не только циклом каждой иглы. Я просматривал этот форум, и у него были похожие вопросы, например:

  • Использование массива в виде игл в strpos
  • Определите несколько игл с помощью stripos
  • Не удается найти массив в PHP in_array для наличия нескольких игл

но предел их был тем, что я ищу. Я использую strpos, чтобы лучше проиллюстрировать мой вопрос, возможно, для этой цели нужно использовать что-то совершенно другое.

Я знаю Zend_Search_Lucene, и мне интересно, если его можно использовать для достижения этого и того, как (просто общая идея)?

Большое спасибо за вашу помощь и время!

Вот пример кода для моей стратегии:

function strpos_array($haystack, $needles, $offset=0) { $matches = array(); //Avoid the obvious: when haystack or needles are empty, return no matches if(empty($needles) || empty($haystack)) { return $matches; } $haystack = (string)$haystack; //Pre-cast non-string haystacks $haylen = strlen($haystack); //Allow negative (from end of haystack) offsets if($offset < 0) { $offset += $heylen; } //Use strpos if there is no array or only one needle if(!is_array($needles)) { $needles = array($needles); } $needles = array_unique($needles); //Not necessary if you are sure all needles are unique //Precalculate needle lengths to save time foreach($needles as &$origNeedle) { $origNeedle = array((string)$origNeedle, strlen($origNeedle)); } //Find matches for(; $offset < $haylen; $offset++) { foreach($needles as $needle) { list($needle, $length) = $needle; if($needle == substr($haystack, $offset, $length)) { $matches[] = $offset; break; } } } return($matches); } 

Я реализовал простой метод грубой силы выше, который будет работать с любой комбинацией игл и стогов сена (а не только слов). Для возможно более быстрых алгоритмов проверьте:

  • Алгоритм сопоставления строк Aho-Corasick

Другое решение

 function strpos_array($haystack, $needles, $theOffset=0) { $matches = array(); if(empty($haystack) || empty($needles)) { return $matches; } $haylen = strlen($haystack); if($theOffset < 0) { // Support negative offsets $theOffest += $haylen; } foreach($needles as $needle) { $needlelen = strlen($needle); $offset = $theOffset; while(($match = strpos($haystack, $needle, $offset)) !== false) { $matches[] = $match; $offset = $match + $needlelen; if($offset >= $haylen) { break; } } } return $matches; } 

Я знаю, что это не отвечает на вопрос OP, но хочет комментировать, так как эта страница находится на вершине Google для strpos с несколькими иглами. Вот простое решение для этого (опять же, это не относится к вопросу OP – извините):

  $img_formats = array('.jpg','.png'); $missing = array(); foreach ( $img_formats as $format ) if ( stripos($post['timer_background_image'], $format) === false ) $missing[] = $format; if (count($missing) == 2) return array("save_data"=>$post,"error"=>array("message"=>"The background image must be in a .jpg or .png format.","field"=>"timer_background_image")); 

Если к массиву $ missing добавлено 2 элемента, это означает, что вход не удовлетворяет ни одному из форматов изображений в массиве $ img_formats. В этот момент вы знаете, что можете вернуть ошибку и т. Д. Это легко можно превратить в небольшую функцию:

  function m_stripos( $haystack = null, $needles = array() ){ //return early if missing arguments if ( !$needles || !$haystack ) return false; // create an array to evaluate at the end $missing = array(); //Loop through needles array, and add to $missing array if not satisfied foreach ( $needles as $needle ) if ( stripos($haystack, $needle) === false ) $missing[] = $needle; //If the count of $missing and $needles is equal, we know there were no matches, return false.. if (count($missing) == count($needles)) return false; //If we're here, be happy, return true... return true; } 

Вернемся к нашему первому примеру, используя вместо этого функцию:

  $needles = array('.jpg','.png'); if ( !m_strpos( $post['timer_background_image'], $needles ) ) return array("save_data"=>$post,"error"=>array("message"=>"The background image must be in a .jpg or .png format.","field"=>"timer_background_image")); 

Конечно, то, что вы делаете после того, как функция возвращает true или false, зависит от вас.

попробуйте выполнить предварительный матч для нескольких

 if (preg_match('/word|word2/i', $str)) 

Проверка нескольких значений strpos

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

 $words = str_word_count($str, 2); $word_position_map = array(); foreach($words as $position => $word) { if(!isset($word_position_map[$word])) { $word_position_map[$word] = array(); } $word_position_map[$word][] = $position; } // assuming $needles is an array of words $result = array_intersect_key($word_position_map, array_flip($needles)); 

Хранение информации (например, игл) в правильном формате улучшит время выполнения (например, поскольку вам не нужно вызывать array_flip ).

Примечание из документации str_word_count :

Для этой функции слово «слово» определяется как строка, зависящая от языка, содержащая алфавитные символы, которые также могут содержать, но не начинаться с символов «» и «-».

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

Вы можете использовать регулярное выражение, они поддерживают операции ИЛИ. Это, однако, сделало бы его довольно медленным, по сравнению с strpos.