菜单开关

周梦康 发表于 2018-01-04 2149 次浏览 标签 : unicode

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

需求

如果需要将可能含有中文的字符串进行拆分成数组,我们下面以 utf-8 编码为例。

解决方案一

我习惯的方法可能是:

mb_internal_encoding("UTF-8");

$str = "周梦康";

$array = [];
for ($i=0,$l = mb_strlen($str); $i < $l; $i++) { 
    array_push($array, mb_substr($str, $i, 1));
}

var_export($array);

假如我们没装mb扩展怎么办?

解决方案二

今天看到一份代码,别人是这么写的:

/* 
 * 将可能含有中文的字符串进行拆分成数组
 */ 
function str_split_utf8($str)  
{  
    $split = 1;  
    $array = array();  
    for ($i = 0; $i < strlen($str);) {  
        $value = ord($str[$i]);  
        if ($value > 127) {  
            if ($value >= 192 && $value <= 223) {  
                $split = 2;  
            } elseif ($value >= 224 && $value <= 239) {  
                $split = 3;  
            } elseif ($value >= 240 && $value <= 247) {  
                $split = 4;  
            }  
        } else {  
            $split = 1;  
        }  
        $key = null;  
        for ($j = 0; $j < $split; $j++, $i++) {  
            $key .= $str[$i];  
        }  
        array_push($array, $key);  
    }  
    return $array;  
}  

代码解读

strlen计算的是字节数,而直接使用$str[x]就沿用了c语言里面char数组和字符串的习惯,表示按字节来读取$str,也就是说每次读取的数据的ascii码值不可能大于255。而php里使用ord来获取ascii码值。

切割规则如下

ascii 码范围切割偏移量
0 ~ 1271 字节
192 ~ 2232 字节
224 ~ 2393 字节
240 ~ 2474 字节

为什么呢?

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
https://segmentfault.com/a/1190000012692022 口语化叙述 utf-8 的来历

Unicode

Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

UTF-8

UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的(能容纳0~127)。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位:

Unicode 符号范围(十六进制)UTF-8 编码方式(二进制)UTF-8 首字节范围
0000 0000-0000 007F0xxxxxxx0 ~ 127
0000 0080-0000 07FF110xxxxx 10xxxxxx(128+64) ~ (255-32) 也就是 192 ~ 223
0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx(128+64+32) ~ (255-16) 也就是 224 ~ 239
0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx(128+64+32+16) ~ (255-8) 也就是 240 ~ 247

想必看了这个表,大家就能明白了吧。

嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表

回复 会编程的小猪 2018-01-05 15:24:24
非常喜欢博主的博客,试一下这个评论功能。。学习学习
回复 周梦康 2018-02-03 12:16:57
回复会编程的小猪: 客气了老铁
回复 薛聪o_O 2018-02-08 15:40:01
回复周梦康: hahah
回复 滔哥 2018-01-08 11:23:26
为嘛我脑子第一反应是给它装一个...
回复 周梦康 2018-02-03 12:16:49
回复滔哥: 哈哈哈,好吧,那也行。
回复 薛聪o_O 2018-01-11 16:22:49
测试,哈哈哈
回复 永-远 2018-03-07 17:18:29
可以试一试用正则匹配中文。
回复 永-远 2018-03-07 17:19:56
我还以为评论支持 markdown 呢,上一条评论不完整,再来一次。
`
回复 永-远 2018-03-07 17:20:14
回复 永-远 2018-03-07 17:21:06


$str = "php是世界上最好的语言";
// fun-1
preg_match_all("/./u",$str,$strArr);
// fun-2
$chars = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
// test
var_dump($strArr);
var_dump($chars);
回复 永-远 2018-03-07 17:23:46
评论测试失败:
1.不支持 markdown;
2.PHP 语法提交代码,啥都不显示;
3.多行代码会转换成一行。
回复 永-远 2018-03-07 17:31:45
回复永-远: 怎么回事,刚才还不换行呢,刷新一下就换行了。
回复 周梦康 2018-03-07 18:54:45
回复永-远: 不好意思,评论只是简单的弄了下,看来扩展了。
回复 王凯波 2018-06-07 09:36:33
很不错的文章,可以对Unicode和UTF-8有更深入的了解