php关键词替换的类(避免重复替换,保留与还原原始链接)
本节主要内容:
一个关键词替换的类
主要可以用于关键词过滤,或关键词查找替换方面。
实现过程分析:
关键词替换,其实就是一个str_replace()的过程,如果是单纯的str_replace面对10W的关键词,1W字的文章也只需要2秒左右。
问题所在:
关键词替换了不只一次,比如a需要替换成<a>a</a>,但结果可能是<a><a>a</a></a>等这样。
为此,需要一个方法保护好已经替换了的标签,那么在处理文章之前,就先把标签替换掉比如[_tnum_]在文章处理好了以后再把它还原。
另外一个问题,如果关键字或文章中有[_tnum_]本身怎么办,那么就需要排除这种这里就不能使用str_replace了而需要用到preg_replace用正则来排除。
第三个问题,如果有两个关键字a和ab怎么办,希望先把长的匹配掉,短后匹配,这样就需要在匹配前先排序。
最后一个问题,当str_replace改成了preg_replace以后,变慢了同样一段话10W次匹配要5秒钟,字符串处理的函数中strpos要快一些,那么先用strpos找出关键词即可,10W次查询还不到1秒。就算是100万才道8秒多。
一个关键词匹配替换的类,代码:
代码示例:
001 | <?php |
002 | /* |
003 | * 关键词匹配类 |
004 | * @author ylx <ylx@gmail.com> |
005 | * @packet mipang |
006 | * 使用实例 |
007 | * $str = "绿壳蛋鸡撒范德萨下一年,下一年的洒落开房间卢卡斯地方军"; |
008 | * $key = new KeyReplace($str,array("xxxx"=>"sadf","下一年"=>'http://baidu.com',"下一年"=>'google.com')); |
009 | * echo $key->getResultText(); |
010 | * echo $key->getRuntime(); |
011 | */ |
012 | class KeyReplace |
013 | { |
014 | private $keys = array (); |
015 | private $text = "" ; |
016 | private $runtime = ; |
017 | private $url = true; |
018 | private $stopkeys = array (); |
019 | private $all = false; |
020 | /** |
021 | * @access public |
022 | * @param string $text 指定被处理的文章 |
023 | * @param array $keys 指定字典词组array(key=>url,...) url可以是数组,如果是数组将随机替换其中的一个 |
024 | * @param array $stopkeys 指定停止词array(key,...) 这里面的词将不会被处理 |
025 | * @param boolean $url true 表示替换成链接否则只替换 |
026 | * @param boolean $all true 表示替换所有找到的词,否则只替换第一次 |
027 | */ |
028 | public function __construct( $text = '' , $keys = array (), $url =true, $stopkeys = array (), $all =false) { |
029 | $this ->keys = $keys ; |
030 | $this ->text = $text ; |
031 | $this ->url = $url ; |
032 | $this ->stopkeys = $stopkeys ; |
033 | $this ->all = $all ; |
034 | } |
035 | /** |
036 | * 获取处理好的文章 |
037 | * @access public |
038 | * @return string text |
039 | */ |
040 | public function getResultText() { |
041 | $start = microtime(true); |
042 | $keys = $this ->hits_keys(); |
043 | $keys_tmp = array_keys ()( $keys ); |
044 | function cmp( $a , $b ){ |
045 | if (mb_strlen( $a ) == mb_strlen( $b )) { |
046 | return ; |
047 | } |
048 | return (mb_strlen( $a ) < mb_strlen( $b )) ? : -; |
049 | } |
050 | usort( $keys_tmp , "cmp" ); |
051 | foreach ( $keys_tmp as $key ){ |
052 | if ( is_array ( $keys [ $key ])){ |
053 | $url = $keys [ $key ][rand(, count ( $keys [ $key ])-)]; |
054 | } else |
055 | $url = $keys [ $key ]; |
056 | $this ->text = $this ->r_s( $this ->text, $key , $url ); |
057 | } |
058 | $this ->runtime = microtime(true)- $start ; |
059 | return $this ->text; |
060 | } |
061 | /** |
062 | * 获取处理时间 |
063 | * @access public |
064 | * @return float |
065 | */ |
066 | public function getRuntime() { |
067 | return $this ->runtime; |
068 | } |
069 | /** |
070 | * 设置关键词 |
071 | * @access public |
072 | * @param array $keys array(key=>url,...) |
073 | */ |
074 | public function setKeys( $keys ) { |
075 | $this ->keys = $keys ; |
076 | } |
077 | /** |
078 | * 设置停止词 |
079 | * @access public |
080 | * @param array $keys array(key,...) |
081 | */ |
082 | public function setStopKeys( $keys ) { |
083 | $this ->stopkeys = $keys ; |
084 | } |
085 | /** |
086 | * 设置文章 |
087 | * @access public |
088 | * @param string $text |
089 | */ |
090 | public function setText( $text ) { |
091 | $this ->text = $text ; |
092 | } |
093 | /** |
094 | * 用来找到字符串里面命中的关键词 |
095 | * @access public |
096 | * @return array $keys 返回匹配到的词array(key=>url,...) |
097 | */ |
098 | public function hits_keys(){ |
099 | $ar = $this ->keys; |
100 | $ar = $ar ? $ar : array (); |
101 | $result = array (); |
102 | $str = $this ->text; |
103 | foreach ( $ar as $k => $url ){ |
104 | $k = trim( $k ); |
105 | if (! $k ) |
106 | continue ; |
107 | if ( strpos ( $str , $k )!==false && !in_array( $k , $this ->stopkeys)){ |
108 | $result [ $k ] = $url ; |
109 | } |
110 | } |
111 | return $result ? $result : array (); |
112 | } |
113 | /** |
114 | * 用来找到字符串里面命中的停止词 |
115 | * @access public |
116 | * @return array $keys 返回匹配到的词array(key,...) |
117 | */ |
118 | public function hits_stop_keys(){ |
119 | $ar = $this ->stopkeys; |
120 | $ar = $ar ? $ar : array (); |
121 | $result = array (); |
122 | $str = $this ->text; |
123 | foreach ( $ar as $k ){ |
124 | $k = trim( $k ); |
125 | if (! $k ) |
126 | continue ; |
127 | if ( strpos ( $str , $k )!==false && in_array( $k , $this ->stopkeys)){ |
128 | $result [] = $k ; |
129 | } |
130 | } |
131 | return $result ? $result : array (); |
132 | } |
133 | /** |
134 | * 处理替换过程 |
135 | * @access private |
136 | * @param string $text 被替换者 |
137 | * @param string $key 关键词 |
138 | * @param string $url 链接 |
139 | * @return string $text 处理好的文章 |
140 | */ |
141 | private function r_s( $text , $key , $url ){ |
142 | $tmp = $text ; |
143 | $stop_keys = $this ->hits_stop_keys(); |
144 | $stopkeys = $tags = $a = array (); |
145 | if (preg_match_all( "#<a[^>]+>[^<]*</a[^>]*>#su" , $tmp , $m )){ |
146 | $a = $m []; |
147 | foreach ( $m [] as $k => $z ){ |
148 | $z = preg_replace( "#\##s" , "\#" , $z ); |
149 | $tmp = preg_replace( '#' . $z . '#s' , "[_a" . $k . "_]" , $tmp ,); |
150 | } |
151 | }; |
152 | if (preg_match_all( "#<[^>]+>#s" , $tmp , $m )){ |
153 | $tags = $m []; |
154 | foreach ( $m [] as $k => $z ){ |
155 | $z = preg_replace( "#\##s" , "\#" , $z ); |
156 | $tmp = preg_replace( '#' . $z . '#s' , "[_tag" . $k . "_]" , $tmp ,); |
157 | } |
158 | } |
159 | if (! empty ( $stop_keys )){ |
160 | if (preg_match_all( "#" .implode( "|" , $stop_keys ). "#s" , $tmp , $m )){ |
161 | $stopkeys = $m []; |
162 | foreach ( $m [] as $k => $z ){ |
163 | $z = preg_replace( "#\##s" , "\#" , $z ); |
164 | $tmp = preg_replace( '#' . $z . '#s' , "[_s" . $k . "_]" , $tmp ,); |
165 | } |
166 | } |
167 | } |
168 | $key = preg_replace( "#([\#\(\)\[\]\*])#s" , "\\\\$" , $key ); |
169 | if ( $this ->url) |
170 | $tmp = preg_replace( "#(?!\[_s|\[_a|\[_|\[_t|\[_ta|\[_tag)" . $key . "(?!ag\d+_\]|g\d+_\]|\d+_\]|s\d+_\]|_\])#us" , '<a href="' . $url . '">' . $key . '</a>' , $tmp , $this ->all?-:); |
171 | else |
172 | $tmp = preg_replace( "#(?!\[_s|\[_a|\[_|\[_t|\[_ta|\[_tag)" . $key . "(?!ag\d+_\]|g\d+_\]|\d+_\]|s\d+_\]|_\])#us" , $url , $tmp , $this ->all?-:); |
173 | if (! empty ( $a )){ |
174 | foreach ( $a as $n => $at ){ |
175 | $tmp = str_replace ( "[_a" . $n . "_]" , $at , $tmp ); |
176 | } |
177 | } |
178 | if (! empty ( $tags )){ |
179 | foreach ( $tags as $n => $at ){ |
180 | $tmp = str_replace ( "[_tag" . $n . "_]" , $at , $tmp ); |
181 | } |
182 | } |
183 | if (! empty ( $stopkeys )){ |
184 | foreach ( $stopkeys as $n => $at ){ |
185 | $tmp = str_replace ( "[_s" . $n . "_]" , $at , $tmp ); |
186 | } |
187 | } |
188 | return $tmp ; |
189 | } |
190 | } |