吃完饭和同事聊天,讨论一个汉字在UTF-8
中占的字节数,网上说有3个的,也有4个的。
我们常用的,在unicode
中,一个汉字的范围是0X4E00
到0x9FA5
,我们常用这个来匹配汉字,我们尝试把0x9FA5
转成UTF-8
,发现还是3
个字节,那么我想问问,到底还有没有4个字节的汉字,是汉字
。?
补充:根据UNICODE
表,发现汉字出现在多个区间内,不仅仅在0X4E00
到0x9FA5
,只能说平时用这个区间来匹配汉字是一种不完美的写法。
吃完饭和同事聊天,讨论一个汉字在UTF-8
中占的字节数,网上说有3个的,也有4个的。
我们常用的,在unicode
中,一个汉字的范围是0X4E00
到0x9FA5
,我们常用这个来匹配汉字,我们尝试把0x9FA5
转成UTF-8
,发现还是3
个字节,那么我想问问,到底还有没有4个字节的汉字,是汉字
。?
补充:根据UNICODE
表,发现汉字出现在多个区间内,不仅仅在0X4E00
到0x9FA5
,只能说平时用这个区间来匹配汉字是一种不完美的写法。
现在已经有四个字节的汉字了,比如这个 \U00020001
。
P.S. 字无法直接写出来,SF 直接拒绝存储这种字了…… ٩(๑`^´๑)۶
当前四个字节汉字的范围是 \U00020000 ~ \U0002B81D
,未来还会不断扩大,它们都是些非常生僻的字。
http://en.wikipedia.org/wiki/CJK_Unified_Ideographs#CJK_Unified_Ideographs_Extension_D
纠正一下 不是0X4E00
到0X9FA5
而是 \u4EOO
到\u9FA5
\u0800 - \uFFFF
这个区间内的unicode,以utf-8
编码存储,都是占3个字节,所以上述区间内的汉字,全部都是3个字节
但utf-8本身支持1-6个字节,用以覆盖需要用4个字节来表示的所有unicode字符
补充回答一下评论里的追问:
‘\u4E00’这是浏览器中的写法吧。
任何语言中unicode都不会以0x
的方式表示,因为0x
一般表示的是16进制的字节,也用来表示在内存和硬盘中的数据。\u4E00
实际上是unicode 的 code point
, 你可以理解为 十六进制的第0x4E00
个(也即进制下的第19968个)unicode字符
unicode只是一个字符集(character set),字符集只规定包含哪些字符以及每个字符的位置,不对应实际的编码(character encoding)
一个字符落地到存储中要有一定的编码方式,utf-8
就是支持unicode的一种编码,实际上\u4E00
这个字符在内存中以utf-8
编码方式存储的话,对应3个字节 0xe4 0xb8 0x80
, 而不是 0x4E00
或者 0x4E 0x00
这也是为什么我说不能用0x
去表示unicode的原因
再举个例子,我
这个汉字,其unicode是\u6211
,在不同编码方式下对应的字节数据分别是
gbk | gb2312 | utf-8 | utf-16 | utf-32 | ascii |
---|---|---|---|---|---|
ce d2 | ce d2 | e6 88 91 | ff fe 11 62 | ff fe 00 00 11 62 00 00 | 不支持 |
与之对应的,我
这个汉字在gbk/gb2312
字符集(对,它们既是字符集的名字,也是编码的名字,其实正统的编码名字应该叫ECU-CN
,但是这个名字已经弱化)中,处于第46区,第50位
,可以写作4650
(区位码),它代表46和50两个十进制数字,而不是四千六百五十,这个区位码
类似于unicode中code point
的概念,是一个字符在特定字符集下的位置或者索引
而ascii字符集
并不收录汉字,所以对应的ascii编码
中无法对这个汉字进行编码
同一个字符集可以对应多种字符编码,比如unicode
就有utf-7 utf-8 utf-16 utf-32
等多种编码,字符编码就是一套如何将字符集中每个字符的索引数据加工成可实际存储、读取的字节数据的规范,编码和索引之间是有数学相关性的,通过一个公式可以计算出来,不同的编码方式使用了不同的公式。
而不同字符集之间,比如gb2312
和unicode
,同一个汉字在这两个字符集中的索引 是没有固定数学关系的,只能通过一个巨大的映射表来进行转换。
在
UNICODE
表中,表明有CJK
的可能就有汉字
,所以不局限于0X4E00
到0x9FA5
,OVER。