LMLPHP后院

使用PHP实现Unicode编码转换为UTF-8编码示例技术

maybe yes 发表于 2016-11-07 22:14

先解释一些概念。Unicode 是 Universal Multiple-Octet Coded Character Set 的简写,简称为UCS。Unicode 是多个八位编组的字符编码集合,它本身只是编码规范,并没有任何实现。目前,大多数 Unicode 编码都是占用两个字节,一共可以编 65536 个字符,全世界所有语言基本上都在里面了,至少绝大多数中文都编进去了,所以很多 json 编码的中文字符串都是用的四个十六进制的数字表示。

UTF-8 编码是对 Unicode 编码的一个实现,是目前世界上使用最广泛的一个编码,最重要的是它兼容 ASCII 和 ISO-8859-1。UTF-8 是以高位分段来区分字符长度的,是一个可变长的编码,最长可以达到 6 个字节。如下示例:

U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

请看如下将 Unicode 转换为 UTF-8 的 PHP 代码实现:

function compatible_decode($unicode) {

    $str = '';
    $arr = array_filter(explode('\\u', $unicode));

    foreach ($arr as $k => $v) {
        if (strlen($v) == 4) {
            $num = (int)hexdec($v);
            $ord_1 = decbin(0xe0 | ($num >> 12));
            $ord_2 = decbin(0x80 | (($num >> 6) & 0x3f));
            $ord_3 = decbin(0x80 | ($num & 0x3f));
            $str .= chr(bindec($ord_1)) . chr(bindec($ord_2)) . chr(bindec($ord_3));
        }else{
            $str .= chr(hexdec($v));
        }
    }

    return $str;
}

上面的代码只对中文和 ASCII 字符做了初步的判断,并没有对每个长度都判断,比如 emoji 就不支持。从上面的代码中可以看出,二进制的移位操作,或运算,与运算在这里特别有用,计算特别方便。中文在 UTF-8 中一般占用三个字节,第一个字节高位以 1110 开头,11100000 不就是 0xe0 吗,与 Unicode 编码中的前 4 位 进行或运算,就达到了上面的 1110xxxx 效果。第二个字节首先使用与运算 0x3f (111111),达到获取 Unicode 编码中的中间 6 位编码,然后同 0x80 (10000000) 进行或运算,达到 10xxxxxx 效果。第三个字节也是如此。最后使用 chr 函数转换为二进制字符数据。测试能够正常将 4 位十六进制和 2 位十六进制 Unicode 编码转换为 UTF-8 编码。

2024-04-16 15:07:46 1713251266 0.007257