【转】刨根究底字符编码之十一——UTF-8编码方式与字节序标记BOM

一、UTF-8编码方式

1.

接下来将分别介绍Unicode字符集的三种编码方式:UTF-8、UTF-16、UTF-32。这里先介绍应用最为广泛的UTF-8。

为满足基于ASCII、面向字节的字符处理的需要,Unicode标准中定义了UTF-8编码方式。UTF-8应该是目前应用最广泛的一种Unicode编码方式(但不是最早面世的,UTF-16要早于UTF-8面世)。

由于UTF-16对于ASCII字符也必须使用两个字节(因为是16位码元)进行编码,存储和处理效率相对低下,并且由于ASCII字符经过UTF-16编码后得到的两个字节,高字节始终是0x00,很多C语言的函数都将此字节视为字符串末尾从而导致无法正确解析文本。

因此,UTF-16一开始推出的时候就遭到很多西方国家的抵制,大大影响了Unicode的推行。于是后来又设计了UTF-8编码方式,才解决了这些问题。

2.

UTF-8的码元由8位单字节组成;在UTF-8中,因为码元较小的缘故,Unicode码点值被映射到一个、两个、三个或四个码元;换言之,UTF-8使用一个至四个8位单字节码元的序列来表示Unicode字符。因此,UTF-8是一种使用单字节码元的变宽(即变长或不定长)码元序列的编码方式。

UTF-8编码方式对所有ASCII码点值(0x00~0x7F)具有透明性。所谓透明性,具体指的是在U+0000到U+007F范围内(十进制为0~127)的Unicode码点值,亦即ASCII字符的Unicode码点值,被直接转换为UTF-8单一字节码元0x00~0x7F,与ASCII码没有区别。

并且,0x00~0x7F不会出现在UTF-8编码的非ASCII字符的首字节与非首字节的任意一个字节中(非ASCII字符的UTF-8编码为由两个或两个以上的单字节码元所组成的码元序列),这样就保证了与早已应用广泛且已成为工业标准的ASCII编码的完全兼容,且避免了歧义,同时纠错能力也强。

(笨笨阿林原创文章,转载请注明出处)

3.

UTF-8同其他的多字节码元编码方式相比具有以下优点:

a) UTF-8的编码空间足够大,未来Unicode新标准收录更多字符,UTF-8也能适应,因此不会再出现UTF-16那样的尴尬。

(注:这里所指的编码空间并不是前文所提到的编号空间Code Space,编号空间属于编号字符集CCS里的概念,而编码空间属于字符编码方式CEF里的概念,两者不能等同;这里的编码空间可理解为编码方式的未来可扩展性、高适应性,详见后文《UTF-8究竟是怎么编码的——UTF-8的编码算法介绍》以及《UTF-16究竟是怎么编码的——UTF-16的编码算法介绍》)

b) UTF-8是变长编码(准确地说是变长码元序列,而码元本身是固定长度为8位单字节的,也就是说,UTF-8采用的是单字节码元),比如一个字节足以容纳所有的ASCII码字符,就用一个字节来存储,不必在高位补0以浪费更多的字节来存储,因此在英语作为国际语言的现实情况下,UTF-8因其ASCII字符的单字节编码这一特性可节省大量存储空间。

c) UTF-8完全直接兼容ASCII码,而非不完全间接兼容。

d) UTF-8的码元序列的第一个字节指明了后面所跟的字节的数目(即带有前缀码),这对字节流的前向解析非常有效(详见后面的附文《UTF-8是怎么编码的——UTF-8的编码算法介绍》)。

e) 也因为UTF-8编码带有前缀码,所以容错性好,即使在传输过程中发生局部的字节错误,比如即便丢失、增加、改变了某些字节,也不会导致所有后续字符全部错乱这样传递性、连锁性的错误问题(否则,若存在错误传递性、连锁性的话,一旦中间某些字节出错,则必须丢弃从出错点开始到结尾的所有编码字节,比如GB码、UTF-32码就是如此),因此很容易重新同步,具有很强的鲁棒性(即健壮性)。

f) 由于UTF-8编码没有状态,从UTF-8字节流的任意位置开始可以有效地找到一个字符的起始位置,字符边界很容易界定、检测出来,所以具有很好的“自同步性”。

g) UTF-8已经成为互联网所采用的字符编码方式的事实标准。

h) UTF-8是字节顺序无关的(因为采用的是单字节码元,而非像UTF-16、UTF-32采用的是多字节码元),它的字节顺序在所有系统中都是一样的,其码元序列与字节序列相同,因此它实际上并不需要字节顺序标记BOM(Byte-Orde Mark),虽然Windows系统经常“多此一举”地加上BOM。(有关字节序标记BOM的介绍见下文)

字节序问题在进行信息交换时会带来不小的麻烦。如果字节序未协商好,将导致乱码;若协商结果为双方一个采用大端一个采用小端,则必然有一方要进行大小端转换,性能损失不可避免(字节序的大小端问题其实不像看起来那么简单,有时会涉及硬件、操作系统、上层应用软件多个层次,可能会导致多次转换,详见前文中有关字节序Byte-Orde的介绍)。

i) 字节FE(二进制为1111 1110)和FF(二进制为1111 1111)在UTF-8编码中永远不会出现(因为UTF-8编码方式中,每个字节只能以0、110、1110、11110或10开头,详见后文介绍)。因此可以用称之为零宽度不中断空格(ZERO WIDTH NO-BREAK SPACE)的字符(Unicode字符名称为U+FEFF)作为字节顺序标记BOM来标明UTF-16或UTF-32文本的字节序。

(注:Windows系统中BOM有时也用在UTF-8编码的文本文件的开头,虽然UTF-8编码并不存在字节序问题,但Windows却用BOM来表明该文本文件的编码格式为UTF-8,这看起来有点“多此一举”,其具体原因详见后文)

j) UTF-8编码可以通过屏蔽位和移位操作快速读写。

k) 字符串比较时strcmp()和wcscmp()的返回结果相同,因此使排序变得更加容易。

4.

UTF-8编码方式也并非完美无缺,大致上有如下缺点:

a) 无法根据字符数直接判断出UTF-8文本的字节数,因为UTF-8是一种变长编码方式(码元虽然固定为8位单字节,但码元序列是变长的,可能是单个码元共8位,比如ASCII字符;也可能是两个码元共16位、三个码元共24位、四个码元共32位等)。因此,无论是计算字符数,还是执行索引操作,效率都不高。

b) 需要用2个字节编码那些在扩展ASCII(即EASCII)字符集中只需1个字节编码的扩展字符。

c) 以8位单字节码元编码的UTF-8字符会被Email网关过滤,因为Internet上的信息传输最初设计为7位ASCII码字符(ASCII仅用到了1个字节的低7位)的传输。因此产生了UTF-7编码(类似于同样为Email传输而设计的Base64编码或quoted-printable编码,由于Base64编码或quoted-printable编码各有其不足,因此又设计了UTF-7编码)。

d) UTF-8在它的表示中使用值100xxxxx的几率超过50%,而现存的实现如ISO 2022、4873、6429和8859编码系统,会把它错认为是C1控制码。因此产生了UTF-7.5编码。

(笨笨阿林原创文章,转载请注明出处)

 

二、字节序标记BOM

1.

在将逻辑形式的码元序列(或可称之为逻辑编码)映射为物理形式的字节序列(或可称之为物理编码)时,因系统平台的差异,存在一个字节序(Byte-Order字节顺序)的问题。而字节序问题的存在,导致在某些场合下,需要对文本字符所采用的字节序予以明确说明。Unicode/UCS规范中所推荐的用于说明字节序的方法是使用BOM字节序标记(Byte-Order Mark字节顺序标记)。

字节序标记BOM采用的是Unicode码点值为FEFF(十进制为65279,二进制为1111 1110 1111 1111)的字符,因此BOM实际上可认为是该字符(U+FEFF)的别名。

最初,字符U+FEFF如果出现在字节流的开头,则用来标识该字节流的字节序——是高位在前还是低位在前;如果它出现在字节流的中间,则表达为该字符的原义——零宽度不中断空格(ZERO WIDTH NO-BREAK SPACE零宽度无断空白)。该字符名义上是个空格,实际上是零宽度的,即相当于是不可见也不可打印字符(平常使用较多的是ASCII空格字符,是非零宽度的,需要占用一个字符的宽度,因此为可见不可打印字符)。

不过,从Unicode 3.2开始,U+FEFF只能出现在字节流的开头,且只能用于标识字节序,就如它的别名——字节序标记——所表示的意思一样;除此以外的用法已被舍弃。取而代之的是,使用U+2060来表示零宽度不中断空格。

2.

如果UTF-16编码的字节序列为大端序,则该字节序标记在字节流的开头呈现为0xFE 0xFF;若字节序列为小端序,则该字节序标记在字节流的开头呈现为0xFF 0xFE。如果UTF-32编码的字节序列为大端序,则该字节序标记在字节流的开头呈现为0x00 0x00 0xFE 0xFF;若字节序列为小端序,则该字节序标记在字节流的开头呈现为0xFF 0xFE 0x00 0x00。

需要特别注意的是,UTF-8编码本身并不存在字节序的问题,但仍然有可能会用到BOM——有时被用来标示某文本是UTF-8编码格式的文本。再强调一遍:在UFT-8编码格式的文本中,如果添加了BOM,则只用它来标示该文本是由UTF-8编码方式编码的,而不用来说明字节序,因为UTF-8编码根本就不存在字节序问题。

3.

许多Windows程序(包含记事本)会添加BOM到UTF-8编码格式的文件中(至于为什么要添加BOM,可参看后续《微软跟联通有仇?》一文)。然而,在类Unix系统中,这种作法则不被建议采用。

因为它会影响到无法识别它的编程语言,如gcc会报告源码文件开头有无法识别的字符;而在PHP中,如果没有激活输出缓冲(output buffering)的话,则它会使得页面内容开始被送往浏览器(即http header头被提交),从而使PHP脚本无法再指定http header头。

对于已在IANA注册的字符编码(实际为字符编码模式CES)UTF-16BE、UTF-16LE、UTF-32BE和UTF-32LE等来说,不可使用BOM,因为其名称本身已决定了其字节顺序。而对于已注册的字符编码UTF-16和UTF-32来说,则必须在文本开头使用BOM。

4.

不同编码的字节序列中所使用的字节序标记BOM本身的字节序列呈现:

(笨笨阿林原创文章,转载请注明出处)

 

三、小结

1.

由于UTF-8编码方式以一个字节(8位)作为码元,属于单字节码元,在计算机处理、存储和传输时不存在字节序问题(字节序问题只跟多字节码元有关),因此避免了平台依赖性,跨平台兼容性好。

它相对于其他编码方式对英语更为友好,同样也对计算机语言(如C++、Java、C#、JavaScript、PHP、HTML等)更为友好。它在处理ASCII等常用字符集时很少会比UTF-16低效。

2.

所以,UTF-8是较为平衡、较为理想的Unicode编码方式。虽然Windows平台由于历史的原因API缺乏对UTF-8的原生支持(Windows原生支持的是UTF-16,因为UTF-16早于UTF-8面世),导致UTF-8推出后的早期使用不广,但目前是应用最为广泛的三大UTF编码方式之一。

因此,应该尽量使用UTF-8(准确地说,应该尽量使用UTF-8 without BOM,即不带字节顺序标记BOM的UTF-8)。

(笨笨阿林原创文章,转载请注明出处)

 

(未完待续)

 

预告:《刨根究底字符编码》系列的下一篇将重点剖析UTF-8究竟是怎么编码的(即UTF-8的编码算法介绍),敬请关注!】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流水灯verilog实验原理_IC设计实例解析之“流水线技术”

源自:微信公众号 “数字芯片实验室”在IC设计中,如果寄存器之间的组合逻辑延时过大,可能会称为设计中的关键路径,从而降低整个电路的工作频率。如下图所示,是一个输入和输出寄存的算术计算逻辑。在set_input_delay和se…

【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的

UTF-8究竟是怎么编码的 1. UTF-8编码是Unicode字符集的一种字符编码方式(CEF),其特点是使用变长字节数(即变长码元序列或称变宽码元序列)来编码。目前一般是1到4个字节,当然,也可以更长。 为什么要变长呢?这可以理解为按需分配…

iphone闪退修复工具_升级 iOS 14.2 微信闪退?iPhone 12 维修贵

原标题:升级 iOS 14.2 微信闪退?iPhone 12 维修贵昨天,苹果推出 iOS 14.2 正式版系统,我相信你们都知道了,主要新增几点功能,并没有针对性解决耗电问题,而对 AirPods Pro 充电进行优化&#xff…

【转】刨根究底字符编码之十三——UTF-16编码方式

1. UTF-16编码方式源于UCS-2(Universal Character Set coded in 2 octets、2-byte Universal Character Set)。而UCS-2,是早期遗留下来的历史产物。 UCS-2将字符编号直接映射为字符编码(CEF,而非CES,详见前文中对现代字符编码模型的解释)&a…

java xml 默认名称空间 xpath_创意产业园办公空间设计

你说想要的样子永远不是现在你的样子,桃花源或许永远在每个人的心底。桃花源办公空间整体外观入口前厅及走廊空间天花板细节桃花源其实是我们每个人或者一群人的乌托邦,一座苏联式的厂房是心中桃花源的开端,光、空、间、穿、行、高、纵、新、…

【转】刨根究底字符编码之十四——UTF-16究竟是怎么编码的

1. 首先要注意的是,代理Surrogate是专属于UTF-16编码方式的一种机制,UTF-8和UTF-32是不用代理的。 如前文所述,为了让UTF-16能继续编码基本平面后面的增补平面中的码点值,于是扩展了UTF-16编码方式。 具体的扩展方法就是为其增…

java环境_配置java环境变量

1.找到此电脑我的电脑右键属性。2.点击高级系统设置。3.点击环境变量。4.点击新建。5.创建变量名JAVA_HOME必须是大写,变量值找到你的jdk的根目录复制下来,然后粘贴进去,点击确定。6.再次点击新建7.创建变量名为path、变量值,找到…

idea+JRebel实现项目热部署

今天发现这个插件,简直神了,太爽了,每次改完代码重启都要等半天,回不去了 第一步:安装插件 第二步:在线生成GUID 网址:在线GUID地址 第三步:打开jrebel 如下所示面板,选…

【转】刨根究底字符编码之十五——UTF-32编码方式

1. UTF-32在UTF目前常用的三种编码方式(UTF-8、UTF-16、UTF-32)中,是最为简单的一种编码方式。UTF-32编码方式不使用任何编码算法将Unicode字符码点值(即编号字符集CCS中的字符编号)转换为码元序列,而是将每个Unicode字符码点值直接表示为一个32位的码元…

小米手机证书信任设置在哪里_小米手机闹钟在哪里?闹钟怎么设置?怎么找到闹钟?...

随着智能手机的大量普及,人们会发现手机里的功能越来越多,绝不像以前那样只能打打电话发发短信那么简单了。而这些功能当中很多我们常用的功能有的人却不会用、不会设置,甚至根本找不到在哪里?比如说手机闹钟这个功能,…

【转】刨根究底字符编码之十六——Windows记事本的诡异怪事:微软为什么跟联通有仇?

1. 当用一个软件(比如Windows记事本或Notepad)打开一个文本文件时,它要做的第一件事是确定这个文本文件究竟是使用哪种编码方式保存的,以便于该软件对其正确解码,否则将显示为乱码。 一般软件确定文本文件编码方式的方法有如下三种&#xf…

win10切换输入法快捷键_输入法失灵怎么办?该怎么恢复?

我们都尝试过在使用win10的时候,输入法无法切换,只能打英文不能输入汉字,对于要打字、打游戏来说都是非常麻烦的。所以,当输入法有问题的时候,应该要怎么样修复?主编:渣渣辉,是兄弟就…

【转】刨根究底字符编码【2.0版】(1):开篇

首先跟大家分享一个有趣的亲身经历。有一次,在网上我看到有程序员发了一个帖子,帖子题目乍一看让人感到惊愕,但细一想又让我会心一笑。 这个帖子的题目大致上是这样的:字符编码是不是让程序员最感到恶心的问题? 更有…

数位dp模板 最高位最低位_无纸化办公入门指南(数位板篇)

居家办公的这段时间,你们有没有遇到无纸化办公的问题?作为一名编辑,在我社规定不能寄纸稿的情况下,看电子稿成了常态。如果是word版尚且可以批注,不影响工作效率。但如果是PDF呢?怎样保证改稿的效率&#x…

AQS

1 AQS抽象的队列同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch 首先AQS维护了一个volatile 修饰的state和一个FIFO的同步队列(多线程争用资源被…

屏幕录像专家6.0_迅捷屏幕录像工具和屏幕录像专家哪个更好用?

随着社会的发展,屏幕录像常常都需要使用,然而有些新手朋友就想知道,到底是电脑中自带的屏幕录像专家好用,还是迅捷屏幕录像工具好用,这两者都是当前使用率比较高的软件,今天小编就为大家分析分析&#xff0…

【转】刨根究底字符编码【2.0版】(2):关键术语解释

上一篇中讲道,字符编码所涉及的面非常广,向下的话,涉及到计算机的底层技术,甚至是硬件实现。 因此,这里就让我们从字符编码涉及到的最基本的术语讲起。大部分术语你可能都已经有了解了,但我们现在从字符编…

Cause: java.sql.SQLSyntaxErrorException: Table ‘Chun.user‘ doesn‘t exist Springboot+MybatisPlus报错

排错:yml配置没问题,可以连接到数据库,导包没问题,数据库里面也有这个库和表, 最终发现是因为表名大小写的问题,因为我直接连接的阿里云服务器上的mysql,而mysql在linux下表名是区分大小写的导…

浏览器字体大小设置_CSS之 浏览器解析样式的过程

阅读本文约需要10分钟大家好,我是你们的导师,经常看我朋友圈的同学应该知道,我每天会在微信上给大家免费提供以下服务!1、长期为你提供最优质的学习资源!2、给你解决技术问题!3、每天在朋友圈里分享优质的技…

angular实现国密算法sm2、sm3和sm4的ts版,基于sm-crypto库实现,前后端实现

ts版,js的话直接根据npm文档调用就可以了! ts提供的方法有问题,所以还换了个思路来实现!而且因为不是nodeJs环境所以const sm4 require(sm-crypto).sm4这个在ts里是报错的导致无法实现,如果是使用的是electron那么使…