strpos () с несколькими иглами? - PullRequest
21 голосов
/ 01 августа 2011

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

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

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

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

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

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

Ответы [ 5 ]

7 голосов
/ 14 января 2016

попробуйте preg match для нескольких

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

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

7 голосов
/ 01 августа 2011

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

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

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


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

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;
}
2 голосов
/ 29 апреля 2013

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

    $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, зависит от вас.

1 голос
/ 01 августа 2011

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

$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 документации:

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

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

0 голосов
/ 01 августа 2011

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

...