PHP中文截取,UTF8和GBK详解 cn_substr_gbk cn_substr_utf8

 
这个是51js上面的文章,替换dedecms的 cn_substr 听说速度更快 ,不过代码 已经通过我自己的测试

$cfg_soft_lang ='utf-8';

/**
 * 中英文截取字符串,汉字安2个字节
 *
 * @access public
 * @param string $str 需要截取的字符串
 * @param int $cutLen 截取的长度
 * @param bool $cutSlashes 是否去掉\
 * @param bool $addSlashes 是加\
 * @param string $oDot 截取后加的字符串,如经常用的三个点
 * @param bool $hasHtml 是否有html
 * @return string
 */

    function cn_substr($str, $cutLen, $oDot = null, $hasHtml = false, $cutSlashes = false, $addSlashes = false)
    {
        global $cfg_soft_lang;
        $str = trim($str);
        if ($cutSlashes) $str = stripslashes($str);
        if ($hasHtml) {
            $str = preg_replace('/(\<[^\<]*\>|\r|\n|\s|\[.+?\])/is','', $str);
            $str = htmlspecialchars($str);
        } else {
            $str = htmlspecialchars($str);
        }
        if ($cutLen && strlen($str) > $cutLen) {
            $nStr ='';
             if ($cfg_soft_lang =='utf-8'){
                $n = 0;
                $tn = 0;
                $noc = 0;
                while ($n < strlen($str)) {
                    $t = ord($str [$n]);
                    if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                        $tn = 1;
                        $n++;
                        $noc++;
                    } elseif (194 <= $t && $t <= 223) {
                        $tn = 2;
                        $n += 2;
                        $noc += 2;
                    } elseif (224 <= $t && $t < 239) {
                        $tn = 3;
                        $n += 3;
                        $noc += 2;
                    } elseif (240 <= $t && $t <= 247) {
                        $tn = 4;
                        $n += 4;
                        $noc += 2;
                    } elseif (248 <= $t && $t <= 251) {
                        $tn = 5;
                        $n += 5;
                        $noc += 2;
                    } elseif ($t == 252 || $t == 253) {
                        $tn = 6;
                        $n += 6;
                        $noc += 2;
                    } else {
                        $n++;
                    }
                    if ($noc >= $cutLen) break;
                }
                if ($noc > $cutLen) $n -= $tn;
                $nStr = substr($str, 0, $n);
            }else{
                for ($i = 0; $i < $cutLen - 1; $i++) {
                    if (ord($str [$i]) > 127) {
                        $nStr .= $str [$i] . $str [$i + 1];
                        $i++;
                    } else {
                        $nStr .= $str [$i];
                    }
                }
            }
        $str = $nStr . $oDot;
}
        if ($addSlashes) $str = addslashes($str);
        $str = htmlspecialchars_decode($str);
        return trim($str);
    }





ecshop 的cn_substr

/**
* 截取UTF-8编码下字符串的函数
*
* @param string $str 被截取的字符串
* @param int $length 截取的长度
* @param bool $append 是否附加省略号
*
* @return string
*/
function sub_str($str, $length = 0, $append = true)
{
$str = trim($str);
$strlength = strlen($str);

if ($length == 0 || $length >= $strlength)
{
return $str;
}
elseif ($length < 0)
{
$length = $strlength + $length;
if ($length < 0)
{
$length = $strlength;
}
}

if (function_exists('mb_substr'))
{
$newstr = mb_substr($str, 0, $length, EC_CHARSET);
}
elseif (function_exists('iconv_substr'))
{
$newstr = iconv_substr($str, 0, $length, EC_CHARSET);
}
else
{
//$newstr = trim_right(substr($str, 0, $length));
$newstr = substr($str, 0, $length);
}

if ($append && $str != $newstr)
{
$newstr .= '...';
}

return $newstr;
}





===========================
下面的转载的文章
2009-10-30 14:56  5356人阅读  评论(2)  收藏  举报
 

 中文字符截取是一个十分有用的功能,在很多地方都会用到,比如提取定长标题,抽取标签等

由于各种字符集的存储方式的不一样,存在双字节(GBK)多字节(Unicode)的存储方式,这就导致了统一处理的困难。

国际标准UTF8字符编码中,存储中文字符要3个字节,即把php文件存储为UTF8编码格式可以得到 strlen("中")=3

假如直接用php的字符串函数去处理类似这个字符将可能产生乱友的情况,主要是由于在一个完整字符中间强制截断产生半字符的情况。要避免这种情况的唯一办法就是把截断位置延长到这个字符结束的位置进行截断

 

 

在PHP中,提供了mbstring模块功能,mbstring以字符作为操作的基本单元,如mb_strlen("中","utf-8")=1 。 大部分的mbstring都要求输入编码,当然可以在php环境中设置默认的编码。参数设置为mbstring.internal_encoding = UTF-8, mbstring.http_input = UTF-8, mbstring.http_output = UTF-8, mbstring.substitute_character = UTF-8。由于php系统一般是存储字节来计算长度的,为了消除mbstring和string之间的差异,使用mbstring的时候就要格外小心 了。

 

假如不使用mbstring的功能 的话,可以自行编写中文字符处理的函数。

php中文截取函数,经网上搜索学习发现,大部分网络中都是以从开始位置一个一个完整字符来实现的。这有可能导致效率十分底。下面我写了个截取函数,是针对UTF8的

[php]  view plain copy
  1. <?php  
  2. $str = "d中-在f在你是d我的国家困g在有和,人。工";  
  3. var_dump(strcut($str,0,9));  
  4. function strcut($str,$start,$len){  
  5.     if($start < 0)  
  6.         $start = strlen($str)+$start;  
  7.       
  8.     $retstart = $start+getOfFirstIndex($str,$start);  
  9.     echo $retstart;  
  10.     $retend = $start + $len -1 + getOfFirstIndex($str,$start + $len);  
  11.     echo $retend;  
  12.     return substr($str,$retstart,$retend-$retstart+1);  
  13. }  
  14. //判断字符开始的位置  
  15. function getOfFirstIndex($str,$start){  
  16.     $char_aci = ord(substr($str,$start-1,1));  
  17.     if(223<$char_aci && $char_aci<240)  
  18.         return -1;  
  19.     $char_aci = ord(substr($str,$start-2,1));  
  20.     if(223<$char_aci && $char_aci<240)  
  21.         return -2;  
  22.     return 0;  
  23. }  
  24. ?>  

224-239是UTF8中文字符高位(第一位,共三位)ascii区间,换算成十六进制为0xE0 - 0xEF 二进制为1100 0000 - 1100 FFFF。通过适当偏移截取位置来避免在一个字符的中间截断的现象。

附UTF8字符编码规则:区间无重复。

 

存储字节数字节流( 二进制)(x为可变位)最高位区间(10进制)低位区间
一字节0xxxxxxx00 - 7F
二字节110xxxxx 10xxxxxxC0 - DF80 - BF
三字节1110xxxx 10xxxxxx 10xxxxxxE0 - EF80 - BF
四字节11110xxx 10xxxxxx 10xxxxxx 10xxxxxxF0 - FF80 - BF

 

 

在GBK字符编码中,存储中文字符要2个字节,即 把php文件存储为ANSI(GBK)编码格式 可以得到 strlen("中")=2

在GBK字符编码中,中文字符最高位指定是1。

GBK 亦采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE之间,剔除 xx7F一条线。总计 23940个码位,共收入 21886个汉字和图形符号,其中汉字(包括部首和构件) 21003个,图形符号 883个。高位和低位有可能相同所以无法判断高低位了。

我们知道,gbk2312编码是 在区位码的区号和位号上分别加上0xA0就得到的,区位码中01-09区是符号、数字区,16-87区是汉字区,10-15和88-94是未定义的空白区。所有汉字的编码为16-87加上0xa0,那么我们可以通过判断大于oxa1来判定是否是一个汉字字符。

php实现如下

[php]  view plain copy
  1. <?php  
  2. $str = "d中-在f在你是d我的国家困g在有和,人。工";  
  3. echo strcut($str,0,9);  
  4. function strcut($str,$start,$len){  
  5.     if($start < 0)  
  6.         $start = strlen($str)+$start;  
  7.       
  8.     $retstart = $start+getOfFirstIndex($str,$start);  
  9.     echo $retstart;  
  10.     $retend = $start + $len -1 + getOfFirstIndex($str,$start + $len);  
  11.     echo $retend;  
  12.     return substr($str,$retstart,$retend-$retstart+1);  
  13. }  
  14. //判断字符开始的位置支持GBK  
  15. function getOfFirstIndex($str,$start){  
  16.     $p = "[".chr(0xa1)."-".chr(0xff)."]+$";  
  17.     preg_match("/$p/",substr($str,$start),$res);  
  18.     if (isset($res[0]) and fmod(strlen($res[0]),2) == 1)  
  19.         return -1;  
  20.     return 0;  
  21. }  
  22. ?>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值