字符串匹配的KMP算法php版

51cto看到这篇介绍KMP的文章,很感兴趣,就花了点时间实践下,关于此算法的原理和解释就不说了【文章地址】 话说编程实践才是真理,老套路,直接上代码

/**
 * @author jiang kejun <jinhua_k9@163.com>
 * @name KMP (Knuth-Morris-Pratt算法) for PHP5
 * @since 2013.5.8
 * @link http://developer.51cto.com/art/201305/392555.htm
 * @version $Id: kmp.php 155 2013.5.8 jkj $
 */
class Kmp
{
	/**
	 * 需查找字符串
	 * @var string
	 */
	var $_n;
	/**
	 * 在这里面找
	 * @var string
	 */
	var $_w;
	
	function __construct( $n, $w ) {
		$this->_n = $n;
		$this->_w = $w;
	}
	
	/**
	 * 输出匹配成功信息
	 * @return void output
	 */
	public function result() {
		$int = $this->firstMatchPoi();
		while ( $int > 0 ){
			$index = $int;
			$int = $this->nextMatchPoi( $int );
			if( $int == 0 ){
				echo "找到了,起始索引为$index!";
				break;
			}
			if( $int == -1 ){
				echo "未找到!";
				break;
			}
		}
	}
	
	/**
	 * 第一个匹配点
	 *
	 * @return int
	 */
	public function firstMatchPoi() {
		return strpos( $this->_w, substr( $this->_n, 0, 1 ) );
	}
	
	/**
	 * 返回下个匹配点的索引值
	 *
	 * @param int $int 当前匹配点
	 * @return int $error
	 */
	public function nextMatchPoi( $int ) {
		$tmp = '';
		$error = 0;
		for( $i = 0;$i < strlen( $this->_n );$i++ ){
			if( substr( $this->_w, ( $int+$i ), 1 ) == $this->_n{$i} ){
				$tmp .= $this->_n{$i};
				//echo "匹配成功,现在为$tmp<br/>";
			}
			else{
				// 最后一个匹配字符对应的"部分匹配值"
				$ws = strlen( $tmp ) - $this->getMatchTab( $tmp );
				$error = $int + $ws;
				if ( substr( $this->_w, $error, 1 ) != substr( $this->_n, 0, 1 ) ){
					$error += 1;
				}
				break;
			}
		}
		// 及时结束
		if ( $error > ( strlen( $this->_w ) - strlen( $this->_n ) ) ){
			$error = -1;
		}
		return $error;
	}
	
	/**
	 * 部分匹配表 (Partial Match Table)
         * 
         * example: 
	 * 		A B C D A B D
	 * 		0 0 0 0 1 2 0
	 * @param string $ss 临时字符
	 * @param bool $last 是否返回最后匹配表数字
	 * @return array
	 */
	public function getMatchTab( $ss, $last=true ) {
		$p = $this->_prefix( $ss );
		$s = $this->_suffix( $ss );
		$match = array();
		foreach( $p as $pkey => $pval ){
			$match[$pkey] = 0;
			foreach( $pval as $key => $val ){
				if( in_array( $val, $s[$pkey] ) ){
					$match[$pkey] = strlen( $val );
				}
			}
		}
		return ( $last==true? end($match) :$match );
	}
	
	/**
	 * 前缀表
	 *
	 * @param string $s
	 * @return array
	 */
	final private function _prefix( $s ) {
		$ss = '';
		$prefix = array();
		$tmp = '';
		for( $i=0; $i < strlen( $s ); $i++ ){
			$ss .= $s{$i};
			for( $j=0; $j < strlen( $ss ); $j++ ){
				$prefix[$i][$j] = $tmp;
				$tmp .= $ss{$j};
			}
			$tmp = '';
		}
		return $prefix;
	}
	
	/**
	 * 后缀表
	 *
	 * @param string $s
	 * @return array
	 */
	final private function _suffix( $s ) {
		$ss = '';
		$suffix = array();
		$suffix[0][0] = '';
		for( $i=1; $i < strlen( $s ); $i++ ){
			$ss .= substr( $s, $i, 1 );
			for( $j=0; $j < strlen( $ss ); $j++ ){
				$suffix[$i][$j] = substr( $ss, $j );
			}
		}
		return $suffix;
	}
}

$sstr = "BBC ABCDAB ABCDABCDABDE";
$rstr = "ABCDABD";
$kmp = new Kmp($rstr, $sstr);
$kmp->result();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值