PHP对中文字符串的指定长度截取一直都是个痛,原因是中文是多字节的,容易截出乱码。对中文英文混合字符串指定长度截取更是不好解决,但只要认真分析还是可以解决的。看本函数:
<?php /** * 功能:按指定长度截取中英文混合字符串 * @param string 待截取的字符串 * @param cnNum 需要截取相当于cnNum个汉字个数的长度 * @param start 可选 起始截取位置(默认0,即从开头开始截取) * @param ifEllipsis 可选 返回的字符串末尾是否需要 .. 点点连接:true是(默认);false否; * @param charset 可选 字符编码:支持 utf-8(默认) 和 gbk * @return 返回截取后的字符串 * @author martinzhang */ function mbSubstrMixStr($string, $cnNum, $start=0, $ifEllipsis=true, $charset='utf-8'){ $start = $start == '' ? 0 : $start; $ifEllipsis = $ifEllipsis===true ? true : false; $charset = $charset=='' ? 'utf-8' : $charset; $code2Len = array('gbk'=>2,'utf-8'=>3); //编码对应每汉字长度(单位:字节) $lenString = mb_strlen($string); //字符串总长度(单位:字节) $LenSplit = $cnNum * $code2Len[strtolower($charset)]; //需求截取长度(单位:字节) $spaceLen = $cnNum * 2; //需求占位(注:每个英文字符为1个占位,每个汉字为2个占位) if($lenString <= $LenSplit){ return $string; }else{ for($i=-1;$i<=$spaceLen;$i++){ $len = $cnNum + $i; //本轮需要截取字符个数 $str=mb_substr($string,$start,$len,$charset); if(strtolower($charset)=='utf-8'){ //如果是utf-8编码 @preg_match_all("/([x{4e00}-x{9fa5}{}¥¨±·×÷ˇˉ‐—―‖‘’“”…ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ∈∏∑√∝∞∠∥∧∨∩∪∫∮∴∵∶∷∽≈≌≠≡≤≥≮≯⊙⊥⌒①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛❶❷❸❹❺❻❼❽❾❿、。〃々〈〉《》「」『』【】〔〕〖〗〝〞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩︰︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹉﹊﹋﹌﹍﹎﹏﹑﹔﹕﹖﹙﹚﹛﹜﹟﹠﹡﹢﹣﹤﹦﹨﹩﹪﹫!"'()+,-/:;<=>?[]_`|~ ̄§×ΘΨ‖‥…№℡←↑→↓↖↗↘↙√∮⊕⊙⊿╱╲▁▂▃▄▅▆▇█▏▔▕■□▲△▼▽◆◇○◎●◢◣◤◥☀☂☃★☆☉☋☍☎☏☑☒☜☞☠☪☭☽☾♀♂♝♞♪♭✁✈✌✍✎✐✔✖✘✙✚✪✲❀❂❈❉❤❦❧〄〠㈜㈱㉿㊙㊚㊛㊣㊤㊥㊦㊧㊨囍]){1}/u",$str,$arrCh); $currentCNs = count($arrCh[0]); //本轮截取到的中文字符个数 }else{ //如果是gbk编码 @preg_match_all("/([x80-xff{}¥¨±·×÷ˇˉ‐—―‖‘’“”…ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ∈∏∑√∝∞∠∥∧∨∩∪∫∮∴∵∶∷∽≈≌≠≡≤≥≮≯⊙⊥⌒①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛❶❷❸❹❺❻❼❽❾❿、。〃々〈〉《》「」『』【】〔〕〖〗〝〞㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩︰︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹉﹊﹋﹌﹍﹎﹏﹑﹔﹕﹖﹙﹚﹛﹜﹟﹠﹡﹢﹣﹤﹦﹨﹩﹪﹫!"'()+,-/:;<=>?[]_`|~ ̄§×ΘΨ‖‥…№℡←↑→↓↖↗↘↙√∮⊕⊙⊿╱╲▁▂▃▄▅▆▇█▏▔▕■□▲△▼▽◆◇○◎●◢◣◤◥☀☂☃★☆☉☋☍☎☏☑☒☜☞☠☪☭☽☾♀♂♝♞♪♭✁✈✌✍✎✐✔✖✘✙✚✪✲❀❂❈❉❤❦❧〄〠㈜㈱㉿㊙㊚㊛㊣㊤㊥㊦㊧㊨囍]){1}/",$str,$arrCh); $currentCNs = floor(count($arrCh[0])/2); //本轮截取到的中文字符个数(注:gbk有别于utf-8) } $chrSpace = $len - $currentCNs; //本轮截取包含非中文字符个数(非中文字符占位数) $currentSpaces = $currentCNs * 2 + $chrSpace; //本轮截取后得到总占位数 $diffSpace = $spaceLen - $currentSpaces; //仍缺少的占位数 if($ifEllipsis==true){ $dot4space = array(2=>'..',3=>'...'); $str .= $dot4space[$diffSpace]; //连接 点点点 if($diffSpace<=3){break 1;} }else{ if($diffSpace<=1){break 1;} } } return $str; } } //使用举例 $Str='本function适用于对1文章2帖子-等‐《标题}按指定长度展示。比如我的展示行最多容得相当于25个汉字长的位置。'; $getStr = mbSubstrMixStr($Str,$cnNum=25); echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />'; echo '原文展示:',$Str.'<br /><br />'; echo '参考刻度:国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国国<br />'; echo '截取效果:',$getStr; ?>