其他分享
首页 > 其他分享> > Unicode和UTF8的区别

Unicode和UTF8的区别

作者:互联网

又来重复造轮子了哈哈,网上看了很多帖子,把自己的理解综合一下,保证一篇看懂!

先放点简介 不想看的话可以直接跳到下面对比

Unicode简介

全称为Universal Multiple-Octet Coded Character Set,简称UCS(通用字符集-Universal Character Set)。
历史上存在两个独立的尝试创立单一字符集的组织,即国际标准化组织(ISO)和多语言软件制造商组成的统一码联盟(http://www.unicode.org)。前者开发的ISO/IEC 10646项目,后者开发的统一码项目。1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode 2.0开始,Unicode采用了与ISO 10646-1相同的字库和字码;ISO也承诺,ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值,以使得两者保持一致。两个项目仍都存在,并独立地公布各自的标准。但统一码联盟和ISO/IEC JTC1/SC2都同意保持两者标准的码表兼容,并紧密地共同调整任何未来的扩展。在发布的时候,Unicode一般都会采用有关字码最常见的字型,但ISO 10646一般都尽可能采用Century字型。
Unicode的编码方式与ISO 10646的通用字符集(UCS)概念相对应,目前的用于实用的Unicode版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节,总共可以组合出65535个不同的字符,这大概已经可以覆盖世界上所有文化的符号。实际上目前版本的Unicode尚未填满这16位编码,保留了大量空间作为特殊使用或将来扩展。如果还不够也没有关系,ISO已经准备了UCS-4方案,说简单了就是四个字节来表示一个字符,这样我们就可以组合出21亿个不同的字符出来(最高位有其他用途)。
由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的字符编码方式,采用4字节编码。UCS包含了已知语言的所有字符。除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、格鲁吉亚语,还包括中文、日文、韩文这样的象形文字,UCS还包括大量的图形、印刷、数学、科学符号。

UTF-8简介

UCS编码虽然定义了每个代码点的编码方式,但是没规定如何传输和存储。比如,在UCS-2码中,英文符号是在ACSII码的前面加上一个0 byte,像“A”的ASCII码 0x41,在UCS码中就是0x0041,这样,对于英文系统来讲会出现大量的0 byte,造成不必要的浪费。而且容易存在对现在的ASCII码不兼容的问题。所以这个重担就落在了UTF编码身上。
于是面向传输的众多UTF(UCS Transfer Format)标准出现了。顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,只不过为了传输时的可靠性,从Unicode到UTF时并不是直接的对应,而是要通过一些算法和规则来转换。
(1)UTF-8(Unicode Transformation Format – 8-bit)
UTF-8是一种针对Unicode的可变长度字符编码(定长码),也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无需或只需做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。
UTF-8使用一至四个字节为每个字符编码:

(2)UTF-16(Unicode Transformation Format – 16-bit)
UTF-16以两个字节为编码单元。在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。Unicode规范中推荐的标记字节顺序的方法是BOM(即字节顺序标记-Byte Order Mark)。在UCS编码中有一个叫做“ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符“ZERO WIDTH NO-BREAK SPACE”又被称作BOM。Windows就是使用BOM来标记文本文件的编码方式的。
UTF-16将0–65535范围内的字符编码成2个字节,如果真的需要表达那些很少使用的”星芒层(astral plane)”内超过这65535范围的Unicode字符,则需要使用一些诡异的技巧来实现。UTF-16编码最明显的优点是它在空间效率上比UTF-32高两倍,因为每个字符只需要2个字节来存储(除去65535范围以外的),而不是UTF-32中的4个字节。并且,如果我们假设某个字符串不包含任何星芒层中的字符,那么我们依然可以在常数时间内找到其中的第N个字符,直到它不成立为止这总是一个不错的推断。其编码方法是:
如果字符编码U小于0x10000,也就是十进制的0到65535之内,则直接使用两字节表示;

(3)UTF-32(Unicode Transformation Format – 32-bit)
使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph),每个数字代表唯一的至少在某种语言中使用的符号的编码方案,称为UTF-32。UTF-32又称UCS-4,是一种将Unicode字符编码的协定,对每个字符都使用4字节。就空间而言,是非常没有效率的。
但这种方法有其优点,最重要的一点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始。虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。

常用软件的默认字符集及其查看方法
(1)window下面保存记事本的文本字符集编码为:系统编码GBK;
(2)linux下面的默认字符集编码查看方法:/etc/sysconfig/i18n;
(3)利用cpdetector第三方包可以判断文件或者流的编码;
(4)查询oracle的默认字符集编码方法:select userenv(‘language’) from dual;
(5)早期操作系统的内码是与语言相关的。现在的Windows在内部统一使用Unicode,然后用代码页适应各种语言;
(6)C、C++、Python2内部字符串都是使用当前系统默认编码;
(7)Python3、Java内部字符串用Unicode保存;
(8)Ruby有一个内部变量$KCODE用来表示可识别的多字节字符串的编码,变量值为”EUC” “SJIS” “UTF8″ “NONE”之一。$KCODE的值为”EUC”时,将假定字符串或正则表达式的编码为EUC-JP。同样地,若为”SJIS”时则认定为Shift JIS。若为”UTF8″时则认定为UTF-8。若为”NONE”时,将不会识别多字节字符串。在向该变量赋值时,只有第1个字节起作用,且不区分大小写字母。”e” “E” 代表 “EUC”,”s” “S” 代表 “SJIS”,”u” “U” 代表 “UTF8″,而”n” “N” 则代表 “NONE”。默认值为”NONE”。即默认情况下Ruby把字符串当成单字节序列来处理;
(9)ultraedit在默认情况下是把utf-8转换为unicode编码,你看到的是unicode编码,
如果你想看到真正的utf-8编码,那么在ultraedit中,做如下操作
File—>conversions—>unicode/asc2/utf-8 to utf-8(asc2 editing)

两者区别

先举个例子,比如CSDN的极客日报,

在unicode字符集中是这样的

C	0043
S	0053
D	0044
N	004E
极	6781
客	5BA2
日	65E5
报	62A5

每个字符对应一个16进制的数字,但计算机只懂0101010的二进制,从unicode的简介里我们知道unicode还有UCS-2的格式,转化为

C	 00000000 01000011
S	 00000000 01010011
D	 00000000 01000100 
N	 00000000 01001110
极	01100111 10000001
客	01011011 10100010 
日	01100101 11100101
报	01100010 10100101
0110011110000001 0101101110100010 0110010111100101 0110001010100101
	极				客				日			报

仔细看发现英文字母里前9位全是0!(第9位一般是奇偶校验所以也是0),太浪费硬盘空间了吧!2G的英文字母就有1G的0还行,这谁顶得住,所以就有了UTF出现了,在UTF-8里是这么做的

UTF-8的标记位

0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
... ...

按照规则来的UTF-8下的CSDN极客日报

C	 01000011
S	 01010011
D	 01000100 
N	 01001110
极	11100110 10011110 10000001
客	11100101 10101110 10100010
日	11100110 10010111 10100101
报	11100110 10001010 10100101

图示不同

还不理解?看图!

img

对比一下unicode的方案,英文短了,中文多了一个字节

汉字二进制转换器网站

思考

为什么会出现各种编码集?其实是为了建立一个映射关系,一个字符对应一个数字,利用一个数字就可以代表一个字符,因为还是那句话,计算机只能处理二进制码010101,而不是我们看的字符(中文也好英文也好,甚至是各种emoji都是字符),所以我们要对字符进行编码咯

来个小彩蛋,在上面那个二进制转换器里可以将emoji通过utf8转换出来哦,是不是加深了对字符编码集的理解?

输入下面的utf8代码

0xF0 0x9F 0x98 0x82
0xF0 0x9F 0x98 0x85
0xF0 0x9F 0x98 0x80
0xF0 0x9F 0x98 0x86

image-20210609113305308

总结

总的来说目的就是utf8就是对unicode字符集的再编码,只是为了节省流量和硬盘罢了

参考资料

(1)维基百科-字符编码
(2)《计算机编码知识——区位码、国标码、机内码、输入码、字形码》
(3)《说说字符集和编码》
(4)《编码简介》
(5)《深入了解字符集和编码》
(6)吴秦 《字符集和字符编码(Charset & Encoding)》

标签:编码,UTF,字节,区别,UTF8,Unicode,字符,UCS
来源: https://blog.csdn.net/weixin_43876186/article/details/117736641