字符串截取很简单,但是像很多网站有些模块显示的地方是截取一部分文字的方式来显示部分文本..
在做模板的时候发现问题,首页截取出来的内容中包含了没有闭合的html标签,结果导致样式或内容显示有问题:
假如有一段字符串,例如:
“Thanks for use <a href=””http://www.wordpress.com”>wordpress</a>”,
如果要截取前面15个字符串,那肯定没问题,如果截取的是20个字符串,那肯定就落在<a>标签里,
这么一来截取后再显示取来的内容就有问题,标签不完整,可能会影响样式..
于是搜索了下,果然有料,腾讯的面试题?:php截取HTML字符串
围观了很久,试了几个贴出来的代码,都不行,人品问题?
索性还是自己写个,思路跟他们不一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
/** * 字符串切割 * * 功能:截取字符串(支持中文),如果字符串中包括<a title="查看与html标签有关的文章" href="http://cuelog.com/tag/html%e6%a0%87%e7%ad%be" target="_blank">html标签</a>,截取的字符串则会保留完整的<a title="查看与html标签有关的文章" href="http://cuelog.com/tag/html%e6%a0%87%e7%ad%be" target="_blank">html标签</a> * 如果截取的字符串中包含不完整的html标签,则从字符串位置0开始截取到html标签前 * * @param string $string * @param int $length * @param string $replace * @return string */ function htmlSubStr ($string, $length = 0, $replace = '…') { // 先截取指定长度的字符串,支持中文 if (strlen ( $string ) < $length) { $string = substr ( $string, 0 ); } else { $char = ord ( $string [$length - 1] ); if ($char >= 224 && $char <= 239) { $string = substr ( $string, 0, $length - 1 ); } else { $char = ord ( $string [$length - 2] ); if ($char >= 224 && $char <= 239) { $string = substr ( $string, 0, $length - 2 ); } else { $string = substr ( $string, 0, $length ); } } } // 开始标签集合,当前开始标签字符串(a,span,div...),结束标签集合 $starts = $start_str = $ends = array (); // 提取截取的字符串中出现的开始标签结合和结束标签集合 preg_match_all ( '/<\w+[^>]*>?/', $string, $starts, PREG_OFFSET_CAPTURE ); preg_match_all ( '/<\/\w+>/', $string, $ends, PREG_OFFSET_CAPTURE ); // 初始化<a title="查看与字符串截取有关的文章" href="http://cuelog.com/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%88%aa%e5%8f%96" target="_blank">字符串截取</a>点 $cut_pos = 0; // 最后追加的字符串 $last_str = ''; if (! empty ( $starts [0] )) { $starts = array_reverse ( $starts [0] ); if (! empty ( $ends [0] )) { $ends = $ends [0]; } foreach ( $starts as $sk => $s ) { // 判断开始标签是否包括XHTML语法的闭合标签<img alt=""> $auto = false; if ($auto != false && $auto = strripos ( $s [0], '/>' )) { // 如果有,则将<a title="查看与字符串截取有关的文章" href="http://cuelog.com/tag/%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%88%aa%e5%8f%96" target="_blank">字符串截取</a>点设置为当前标签的起始位置 if ($cut_pos < $auto) { $cut_pos = $s [1]; $last_str = $s [0]; unset ( $starts [$sk] ); } } else { // 提取开始标签名:a,div,span... preg_match ( '/<(\w+).*>?/', $s [0], $start_str ); if (! empty ( $ends )) { foreach ( $ends as $ek => $e ) { // 提取结束标签名 $end_str = trim ( $e [0], '</>' ); // 如果开始标签名与结束标签名一致,并且结束标签的索引值比开始标签的索引值大,则该标签是完整的有效. if ($end_str == $start_str [1] && $e [1] > $s [1]) { // 如果字符串截取点还没有确定,给它赋值 if ($cut_pos < $e [1]) { $cut_pos = $e [1]; // 并且将闭合标签作为最后的字符串追加 $last_str = $e [0]; } // 将这个正确的标签去掉结束标签,并且滚入下一个开始标签的判断 unset ( $ends [$ek] ); break; } } } else { /* * 如果empty($ends),说明第一个开始标签没有对应的闭合标签 说明这一段截取的内容不完整,只能将字符串截取到第一个开始标签前为止 */ $last_str = ''; $cut_pos = $s [1]; } } } // 拼凑剩余的字符串 $res_str = substr ( $string, 0, $cut_pos ) . $last_str; $less_str = substr ( $string, strlen ( $res_str ) ); $less_pos = strpos ( $less_str, '<' ); $less_str = $less_pos !== false ? substr ( $less_str, 0, $less_pos ) : $less_str; $string = $res_str . $less_str . $replace; } return $string; } $str = 'Welcome to hello world,<div class="http://www.baidu.com" class="title">Hey, guys..<b>Hello</b>Look at thie picture<img src="http://www.baidu.com/test.jpg" class="image" /><span><a href="#">Just so so..</a></span></div>Yeah, U R right.<div class="footer">About</div><span>Follow us..<a href="http://www.facebook.com">FB</a></span>'; echo htmlSubStr ( $str, 260 ); // Welcome to hello world,<div class="http://www.baidu.com" class="title">Hey, guys..<b>Hello</b>Look at thie picture<img src="http://www.baidu.com/test.jpg" class="image" /><span><a href="#">Just so so..</a></span></div>Yeah, U R right.<div class="footer">About</div> |