昨天看了阮一峯老師的一篇博客《字符串匹配的KMP算法》,講的很是棒。這篇文章也是解決了:php
有一個字符串"BBC ABCDAB ABCDABCDABDE",裏面是否包含另外一個字符串"ABCDABD"?
後來發現,其實這不是就PHP自帶函數strpos的功能嗎?因而突發奇想,本身寫個類,實現一下這個算法。算法
代碼數組
<?php class KMP { public $haystack; public $needle; private $_haystackLen; private $_needleLen; private $_matchTable; private $_isMatch; //構造函數 function __construct($haystack,$needle) { $this->haystack = $haystack; $this->needle = $needle; } //初始化一些參數 private function init(){ $this->_haystackLen = $this->getLen($this->haystack); $this->_needleLen = $this->getLen($this->needle); $this->_matchTable = $this->getMatchTable(); $this->_isMatch = false; } //相似strpos函數功能 public function strpos() { $this->init(); //haystack $haystackIdx = $matchNum = 0; while ($haystackIdx <= $this->_haystackLen - $this->_needleLen){ //needle $needIdx = 0; for (; $needIdx < $this->_needleLen; $needIdx++){ if (strcmp($this->haystack[$haystackIdx],$this->needle[$needIdx]) <> 0){ if ($matchNum > 0){ $lastMatchValue = $this->getLastMatchValue($needIdx-1); $haystackIdx += $this->getStep($matchNum,$lastMatchValue); $matchNum = 0; } else { $haystackIdx++; } break; } else { $haystackIdx++; $matchNum++; if ($matchNum == $this->_needleLen){ $this->_isMatch = true; break; } } } if($this->_isMatch == true){ break; } } return $this->_isMatch ? $haystackIdx - $this->_needleLen : false; } //獲取字符長度 private function getLen($str) { return mb_strlen($str,'utf-8'); } //獲取部分匹配表 private function getMatchTable() { $matchTable = []; for ($i=0; $i < $this->_needleLen; $i++){ $intersectLen = 0; $nowStr = mb_substr($this->needle,0,$i + 1,'utf-8'); $preFixArr = $this->getPreFix($nowStr); $sufFixArr = $this->getSufFix($nowStr); if($preFixArr && $sufFixArr){ $intersectArr = array_intersect($preFixArr,$sufFixArr); if (!empty($intersectArr)){ $intersect = array_pop($intersectArr); $intersectLen = mb_strlen($intersect,'utf-8'); } } $matchTable[$i] = $intersectLen; } return $matchTable; } //獲取前綴數組 private function getPreFix($str) { $outArr = []; $strLen = $this->getLen($str); if ($strLen > 1){ for ($i = 1;$i < $strLen; $i++){ $outArr[] = mb_substr($str,0,$i,'utf-8'); } } return $outArr; } //獲取後綴數組 private function getSufFix($str) { $outArr = []; $strLen = $this->getLen($str); if ($strLen > 1){ for ($i = 1;$i < $strLen; $i++){ $outArr[] = mb_substr($str,$i,null,'utf-8'); } } return $outArr; } //計算步長 private function getStep($matchNum,$lastMatchValue) { return $matchNum - $lastMatchValue; } //獲取最後匹配值 private function getLastMatchValue($index) { return isset($this->_matchTable[$index]) ? $this->_matchTable[$index] : 0; } } $str = 'BBC ABCDAB ABCDABCDABDE'; $subStr = 'ABCDABD'; $kmp = new KMP($str,$subStr); var_dump($kmp->strpos()); $kmp->haystack = 'i believe'; $kmp->needle = 'lie'; var_dump($kmp->strpos()); $kmp->haystack = 'i love u'; $kmp->needle = 'hate'; var_dump($kmp->strpos());