3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPで文字列検索のBoyer Moore法

Posted at

PHPで文字列検索のBoyer Moore法

戻り量を考慮していなかったので無限ループや末尾の取り扱いで苦戦した。



/*
Boyer Moore法
見つけたい文字(パターン)の末尾から探していく
テキストの頭から進める。
パターンに含まれて居ない文字の場合はパターンの数分ずらす
パターンに含まれている場合は、最小限の移動
 */
mb_internal_encoding("UTF-8");
//日本語
//①全部同じ
var_dump(bMSearch('テストトテスト', 'テストトテスト'));                            //true
echo '<br>';
//②最初でマッチ
var_dump(bMSearch('テストトテストトトト', 'テストトテスト'));                      //true
echo '<br>';
//③途中でマッチ
var_dump(bMSearch('テストトテストストトテストテテテテテ', 'テストトテスト'));       //true
echo '<br>';
//④途中でマッチ
var_dump(bMSearch('aaaabdfdsrtatテストトテストストトテストテ', 'テストトテスト')); //true
echo '<br>';
//⑤最後でマッチ
var_dump(bMSearch('テストトテテストトテスト', 'テストトテスト'));                  //true
echo '<br>';
//⑥最後でマッチ2
var_dump(bMSearch('テストトテnトテストトテスト', 'テストトテスト'));               //true
echo '<br>';
//⑦最後でマッチ3
var_dump(bMSearch('テストトテスnテストトテスト', 'テストトテスト'));               //true
echo '<br>';
//⑧見つけたい文字よりも短い
var_dump(bMSearch('テスト', 'テストトテスト'));                                   //false
echo '<br>';
//⑨一致しない
var_dump(bMSearch('テストトテス', 'テストトテスト'));                             //false
echo '<br>';
//⑩一致しない
var_dump(bMSearch('後戻りを考慮せず無限ループではまる', 'テストトテスト'));                             //false

function bMSearch($text, $pattern) {
    $tLength   = mb_strlen($text);    //テキストの長さ
    $pLength   = mb_strlen($pattern); //パターンの長さ
    $shifTable = array();             //シフトする量のマスタテーブル

    //シフトテーブルの作成。末尾の1個前まで実施
    for ($i = 0; $i < $pLength - 1; $i++) {
        //キーはパターンの文字。値はシフト量
        $shifTable[mb_substr($pattern, $i, 1, 'UTF-8')] = $pLength - $i -1;
    }
    //パターンの末尾のみの計算。もし、既に文字がある場合は何もしない。最初のfor分でやるとシフト量が0になるため
    if (!array_key_exists(mb_substr($pattern, $pLength-1, 1, 'UTF-8'), $shifTable)) {
        $shifTable[mb_substr($pattern, $pLength-1, 1, 'UTF-8')] = $pLength;
    }

    //var_dump($shifTable);
    //exit('');
    //探索する
    //テキストのindexをパターンの末尾とあわせる。末尾から探索していく
    $tIndex = $pLength -1;
    while ($tIndex < $tLength) {
        //パターンの末尾位置
        $pp = $pLength - 1;
        //文字が一致している間実施
        while (mb_substr($text, $tIndex, 1, 'UTF-8') == mb_substr($pattern, $pp, 1, 'UTF-8')) {
            if ($pp == 0) {
                //探索成功
                return true;
            }
            $tIndex--;
            $pp--;
        }
        //移動する
        if (isset($shifTable[mb_substr($text, $tIndex, 1, 'UTF-8')])) {
            //後戻り対策。大きい方を取る
            $tIndex = $tIndex + MAX($shifTable[mb_substr($text, $tIndex, 1, 'UTF-8')], $pLength - $pp);
        } else {
            //パターン以外の文字の時
            $tIndex = $tIndex + $pLength;
        }
    }
    //探索失敗
    return false;
}



参考サイト

http://tokyo-ct.net/usr/kosaka/for_students/jissen1/akiyojissen1/kougi17.html
http://www.comp.cs.gunma-u.ac.jp/~koichi/ALG2/9beamerBM.pdf
http://www.comp.cs.gunma-u.ac.jp/~koichi/ALG2/ALG2.html

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?