字符串匹配算法——Sunday(PHP实现)

2019-04-13  本文已影响0人  过往云技

Sunday 算法(尽可能的移动最大长度)

Sunday算法是从前往后匹配,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符

文本串第1个字符 s != 模式串第1个字符 e,那么关注文本串中参加匹配的未位字符下一个字符: a


image.png

a 在 ea 字符串的最后一位,则移动位= 0 + 1 = 2(模式串长度) - 1(a 在模式串最后出现位置)= 1


image.png
模式串向右移动 1 位,使上下文的 a 对齐
image.png

匹配成功

代码现实

<?php


namespace Patterns\Algorithm;

/**
 * 如果该字符没有在主模式字符串中出现则跳过,移动位 = 匹配字符串长度 + 1
 * 该字符在主模式字符串中出现,
    1)移动位 = 该字符在模式串中最后出现位置距末端长度 + 1
    2)移动位 = 模式串长度 - 该字符在模式串中最后出现位置
 * Class Sunday
 * @package Patterns\Algorithm
 */
class Sunday
{
    public $_needleLen;
    public $_haystackLen;
    public $_table;

    /**
     * 返回 -1 表示无法匹配,否则返回首次出现位置
     *
     * @param string $haystack
     * @param string $needle
     * @return int
     */
    public function strpos(string $haystack, string $needle):int
    {
        $this->_haystackLen = strlen($haystack);
        $this->_needleLen = strlen($needle);

        if($this->_needleLen > $this->_haystackLen){
            return null;
        }

        $this->prefixTable($needle);
        $p = $this->_haystackLen - $this->_needleLen;
        $s = 0;
        while ($s <= $p){
            $j = 0;
            while ($haystack[$s + $j] == $needle[$j]){
                $j += 1;
                if($j == $this->_needleLen){
                    return $s;
                }
            }

            $haystackIndex = $s + $this->_needleLen;
            if(!isset($haystack[$haystackIndex]))
                break;

            $hIndexText = $haystack[$haystackIndex];
            $s += (isset($this->_table[$hIndexText]) ? $this->_table[$hIndexText] : $this->_needleLen);
        }

        return -1;
    }

    /**
     * 匹配所有出现位置
     * @param string $haystack
     * @param string $needle
     * @return array
     */
    public function strapos(string $haystack, string $needle):array
    {
        $this->_haystackLen = strlen($haystack);
        $this->_needleLen = strlen($needle);

        if($this->_needleLen > $this->_haystackLen){
            return null;
        }

        $this->prefixTable($needle);
        $p = $this->_haystackLen - $this->_needleLen;
        $s = 0;

        $pos = [];
        while ($s <= $p){
            $j = 0;
            while (isset($needle[$j]) && $haystack[$s + $j] == $needle[$j]){
                $j += 1;
                if($j == $this->_needleLen){
                    array_push($pos, $s);
                }
            }

            $haystackIndex = $s + $this->_needleLen;
            if(!isset($haystack[$haystackIndex]))
                break;

            $hIndexText = $haystack[$haystackIndex];
            $s += (isset($this->_table[$hIndexText]) ? $this->_table[$hIndexText] : $this->_needleLen);
        }

        return $pos;
    }

    /**
     * 模式串字符表
     * @param string $needle
     */
    public function prefixTable(string $needle)
    {
        for($i=0; $i < $this->_needleLen; $i++){
            //字符最后出现的位置距末端长度:字符串长度 - 字符当前位置
            $this->_table[$needle[$i]] = $this->_needleLen - $i;
        }

    }

}


$haystack = 'search title.';
$needle = 'w';

$obj = new Sunday();
$index = $obj->strpos($haystack, $needle);

echo $index . PHP_EOL;

var_export($obj->strapos($haystack, $needle));

echo strpos($haystack, $needle) . PHP_EOL;
上一篇 下一篇

猜你喜欢

热点阅读