假如有一段字符串,例如:
Thanks for use <a href="http://www.wordpress.com><span class="link"></span>wordpress</a>"
如果要截取前面15个字符串,那肯定没问题,如果截取的是20个字符串,那肯定就落在<a>标签里,这么一来截取后再显示取来的内容就有问题,标签不完整,可能会影响样式。
下面的方法可以解决php截取文本时,不会讲html标签截断:
/**
* 字符串切割
*
* 功能:截取字符串(支持中文),如果字符串中包括<a title="查看与html标签有关的文章" href="https://5.jimth.com" target="_blank">html标签</a>,截取的字符串则会保留完整的<a title="查看与html标签有关的文章" href="https://5.jimth.com" 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<
