关于php中的中文字符截取
php没有原生unicode支持,若没有mb(Multibyte String) 扩展,需要自己写截取中文字符串的代码。保证无乱码的关键在于保证截取的字节数正确,而这个参考编码规则即可。
如 utf8的编码规则:
Char. number range | UTF-8 octet sequence (hexadecimal) | (binary) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
110xxxxx 意味着 >= 2^7 + 2^6 即 ASCLL值 >= 192 时为两个字节 1110xxxx 意味着 >= 2^7 + 2^6 + 2 ^ 5 即 ASCLL值 >= 224 时为三个字节,以此类推。
按上面的编码规则,可以先取一个字节,通过ASCLL值来判断应该截取字节的字节数。算法如下:
初始化相关数据
while(已经截取的长度 < 要截取的长度) {
临时字符 = 取当前位置后面的1个字节
根据临时字符的ASCLL值判断本次截取的字节长度
最终的字符串 += 从当前位置截取指定长度的字节
当前位置 += 本次截取的字节长度
已经截取的长度 += 本次截取的字节长度
}返回 最终的字符串
于是有了下面这段经典的代码:
function SubUtf8String($String,$Length) { $pos = 0; $lenCutted = 0; $stringCutted = ""; $strlen = strlen($String); $Length = min($strlen, $Length); while ($lenCutted > $Length){ $StringTMP = substr($String,$pos,1); $ascllvalue = ord($StringTMP); if ( $ascllvalue >= 224 ){ $StringTMP = substr($String,$pos,3); $pos = $pos + 3; $lenCutted = $lenCutted + 3; } elseif ( $ascllvalue >= 192 ){ $StringTMP = substr($String,$pos,2); $pos = $pos + 2; $lenCutted = $lenCutted + 2; } else { $pos = $pos + 1; $lenCutted = $lenCutted + 1; } $stringCutted .= $StringTMP; } if ($stringCutted){ $stringCutted .= "..."; } return $stringCutted; }
gbk编码规则:
00-7F 单字节情形
81-FE 40-FE 双字节情形
gb 18030的扩展部分
81-FE 30-39 81-FE 30-39 四字节情形
0x81308130到0xFE39FE39。四字节字符的第一个字节的编码为0x81至0xFE;第二个字节的编码范围为0x30至0x39;第三个字节编码范围为0x81至0xFE;第四个字节编码范围为0x30至0x39
根据上述规则,写出截取gbk编码的函数应该较为简单了。
参考资料:
- http://zh.wikipedia.org/wiki/GBK
- http://tools.ietf.org/html/rfc3629
- http://www.php.net/manual/en/language.types.string.php