24

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

  1. 能够接受多针。我的意思是成千上万的针。
  2. 在大海捞针中搜索所有出现的针并返回一个起始位置数组。

当然,它必须是一种有效的解决方案,而不仅仅是通过每根针的循环。我搜索了这个论坛,也有类似的问题,比如:

但他们都不是我要找的。我使用 strpos 只是为了更好地说明我的问题,可能为此目的必须使用完全不同的东西。

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

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

4

6 回答 6

9

尝试多个预匹配

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

检查多个 strpos 值

于 2016-01-14T19:32:55.740 回答
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;
}
于 2011-08-01T09:56:56.510 回答
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"));

如果将 2 个项目添加到 $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;
    }

回到我们使用 then 函数的第一个示例:

    $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 之后你做什么取决于你。

于 2013-04-29T09:42:24.593 回答
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”被定义为包含字母字符的区域设置相关字符串,它也可以包含但不能以“'”和“-”字符开头。

因此,请确保您设置了正确的语言环境。

于 2011-08-01T10:21:55.497 回答
0

您可以使用正则表达式,它们支持 OR 操作。然而,与 strpos 相比,这将使其相当慢。

于 2011-08-01T09:42:01.543 回答
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
)
于 2021-04-21T23:29:13.213 回答