PHP字符截取无乱码与详细注释

/*
utf-8中文截取无乱码

思路:
如果你看到如下字节,
42 DC 34 af aa

想截取无乱码,那就说明,你知道
从42开始截几个字节,作为一个字符.

比如截1个,截取出来42

再从DC截,你得知道,从DC,往后是几个字节组成了一个字符.

...
...

类推,这样,截取出来的字节才能保证,正是是一个个的字符

所以,关键在于,如何判断一个utf-8字符的字节数?


答: 可以到wiki上查询utf-8的编码规范,那是最权威的.
查阅后得知

最高字节
0xxx xxxx ,1个字节
110xx xxxx , 2个字节
1110 xxxx, 3
1111 0xxxx 4...

*/
$str = '中华人aaaa民共b和国,万c岁';
/*
$str 是待截取的字符串
$len 是截取的字符数
*/

function utf8sub($str,$len) {
    if($len <= 0) {
        return '';
    }
    $length = strlen($str); //待截取的字符串字节数

    // 先取字符串的第一个字节,substr是按字节来的
    $offset = 0; // 这是截取高位字节时的偏移量
    $chars = 0;  // 这是截取到的字符数
    $res = '';   // 这是截取的字符串

    while($chars < $len && $offset < $length) { //只要还没有截取到$len的长度,就继续进行
        $high = decbin(ord(substr($str,$offset,1))); // 重要突破,已经能够判断高位字节

        if(strlen($high) < 8) {
            // 截取1个字节
            $count = 1;
        } else if(substr($high,0,3) == '110') {
            // 截取2个字节
            $count = 2;

        } else if(substr($high,0,4) == '1110') {
            // 截取3个字节
            $count = 3;

        } else if(substr($high,0,5) == '11110') {
            // 截取4个字节
            $count = 4;

        }  else if(substr($high,0,6) == '111110') {
            // 截取5个字节
            $count = 5;

        }  else if(substr($high,0,7) == '1111110') {
            // 截取6个字节
            $count = 6;
        }        

        // echo $count,'<br />';
        $res .= substr($str,$offset,$count);
        $chars += 1;
        $offset += $count;
    
    }
    return $res;
}

echo utf8sub($str,200);

/***


位运算效果会更好.

110x xxxx & 1110 0000 -> 1100 0000
1110 xxxx & 1111 0000 -> 1110 0000



***/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章