web-dev-qa-db-ja.com

複数の針を持つstrpos()?

2つの重要な違いがあるstrpos()のような関数を探しています。

  1. 複数の針を受け入れることができるようにするため。私は1つで何千もの針を意味します。
  2. 干し草の山の中の針のすべての出現を検索し、開始位置の配列を返すため。

もちろん、それはすべての針をループするだけでなく、効率的な解決策でなければなりません。私はこのフォーラムを検索しましたが、次のような同様の質問がありました。

しかし、それらのどれも私が探していたものではありませんでした。私は自分の質問をよりよく説明するためにstrposを使用しています。おそらく、この目的のためにまったく異なるものを使用する必要があります。

私は Zend_Search_Lucene を知っていますが、これを達成するために使用できるかどうか、そしてどのように(一般的な考え方だけ)?

あなたの助けと時間をどうもありがとう!

22

複数のpregマッチを試してください

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

複数のstrpos値をチェックしています

7
user3270784

これが私の戦略のサンプルコードです:

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

私はこれがOPの質問に答えないことを知っていますが、このページは複数の針を持つstrposについてGoogleの上部にあるので、コメントしたいと思いました。これを行うための簡単な解決策は次のとおりです(繰り返しますが、これは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;
    }

代わりに関数を使用して最初の例に戻ります。

    $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を返した後に何をするかは、あなた次第です。

2

単語全体を検索しているようです。この場合、このようなものが役立つかもしれません。組み込み関数を使用するため、カスタムコードよりも高速である必要がありますが、プロファイルを作成する必要があります。

$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」は、アルファベット文字を含むロケール依存の文字列として定義されます。アルファベット文字には、「 '」および「-」文字を含めることもできますが、これらの文字で始めることはできません。

したがって、ロケールを正しく設定してください。

1
Felix Kling

正規表現を使用できます。これらはOR操作をサポートします。ただし、これにより、strposと比較してかなり遅くなります。

0
TJHeuvel