strpos()有多针?

时间:2011-08-01 09:38:42

标签: php full-text-search full-text-indexing strpos

我正在寻找像strpos()这样的函数,它有两个显着的区别:

  1. 能够接受多针。我的意思是成千上万针。
  2. 搜寻大海捞针中出现的所有针头并返回一系列起始位置。
  3. 当然,它必须是一种有效的解决方案,而不仅仅是每根针的循环。我搜索了这个论坛,并且有类似的问题,如:

    但是我们正在寻找它们。我使用strpos只是为了更好地说明我的问题,可能有一些完全不同的东西必须用于此目的。

    我知道Zend_Search_Lucene并且我感兴趣的是它是否可以用来实现这个以及如何(只是一般的想法)?

    非常感谢你的帮助和时间!

6 个答案:

答案 0 :(得分:7)

以下是我的策略的一些示例代码:

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

答案 1 :(得分:7)

尝试多个匹配的匹配

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

Checking for multiple strpos values

答案 2 :(得分:2)

我知道这不会回答OP的问题但是想发表评论,因为这个页面位于谷歌的顶部,用于多针的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"));

如果将$ items添加到$ missing数组,这意味着输入不满足$ 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之后你所做的是取决于你。

答案 3 :(得分:1)

您似乎正在搜索整个单词。在这种情况下,这样的事情可能会有所帮助。由于它使用内置函数,它应该比自定义代码更快,但您必须对其进行分析:

$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文档:

  

为了这个函数的目的,'word'被定义为一个包含字母字符的语言环境依赖字符串,它也可能包含但不能以“'”和“ - ”字符开头。

因此,请确保将语言环境设置为正确。

答案 4 :(得分:0)

您可以使用正则表达式,它们支持OR运算。然而,与strpos相比,这会使它相当慢。

答案 5 :(得分:0)

使用 array_map() 的简单解决方案怎么样?

$string = 'one two three four';
$needles = array( 'five' , 'three' );
$strpos_arr = array_map( function ( $check ) use ( $string ) {
    return strpos( $string, $check );
}, $needles );

作为返回,您将拥有一个数组,其中键是针位置,值是起始位置(如果找到)。

//print_r( $strpos_arr );
Array
(
    [0] => 
    [1] => 8
)