从 ASCII 到 UTF-8 - Unicode 码的诞生与实现

news2024/11/16 5:42:53

前言:最近我在整理过往笔记时,发现涉及到了 UTF-8、Unicode
的相关内容,相信大家中的很多人和之前的我一样,在过去的很长一段时间里,并没有搞清楚什么是 Unicode、什么是
UTF-8,于是就有了这篇文章,我将带大家梳理一下关于 Unicode 码的诞生与实现,用正确的姿势学习认识 Unicode 和
UTF-8。


文章目录

      • 1、ASCII 码
      • 2、Unicode 码
      • 3、UTF-8
        • 3.1、Unicode 码和 UTF-8 的关系
        • 3.2、UTF-8 具体实现
        • 3.3、UTF-8 具体实现的详细解读
        • 3.4、问题 1 : 为什么第 n+1 位是 0 呢 ?
        • 3.5、问题 2 : 为什么 2 字节及以上包括的 UTF-8 编码 ,低字节的高 2 位始终是固定的 10 呢 ?


1、ASCII 码

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。ASCII 第一次以规范标准的类型发表是在 1967 年,最后一次更新则是在 1986 年,到目前为止共定义了 128个 字符。

由于计算机最开始就是由欧美国家发明使用的,所以在计算机发展早期,需要显示在电脑屏幕的字符并不多,也就是英文字母、数字、标点符号和一些特殊符号、特殊字符就完全可以满足使用上的需求,总共加起来一个字节足矣表示完。因此就出现了 ASCII 码。

ASCII 码是从零开始编号,一直到 127 号,用于表示完上述所有的字符。其中 0~31 及 127(共 33 个)是控制字符或通信专用字符(其余为可显示字符):

  • 控制符: LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;
  • 通信专用字符: SOH(文头)、EOT(文尾)、ACK(确认)等。

image-20240122103637887

32~126(共 95 个)是字符(32 是空格),其中 48~57 为 0 到 9 十个阿拉伯数字。65~90 为 26 个大写英文字母,97~122 号为 26 个小写英文字母,其余为一些标点符号、运算符号等。

这就是 ASCII 码。

2、Unicode 码

随着计算机在全世界的发展和流行,越来越多的国家开始接触和使用到了计算机,此时的 ASCII 码便开始不再适用,因为对于很多非英语国家来说,即使计算机界面再人性化,不能使用自己看得懂的语言,也是无济于事。

因此 Unicode 码就诞生了。

Unicode(Universal Multiple-Octet Coded Character Set,通用多八位编码字符集),简称 UCS,国际标准编号 ISO/IEC 10646,是由 ISO 和 IEC 两家国际标准组织联合成立的工作组设计的一套新的统一字符集项目,目的与 Unicode 联盟一样致力于开发一款全世界通用的编码集。

早在 1984 年 ISO 和 IEC 两家组织就成立了一个联合工作组来设计一套新的统一字符集标准,但是这两个组织都不知道对方的存在,直到 Unicode 联盟 1988 年发布了 Unicode 草案(UCS 草案 1989 年发布),才发现大家在做同一件事,没有必要搞两套标准所以后面又考虑合并。

ISO 规定,必须用两个字节,也就是 16 位二进制来统一的表示所有的字符。这 16 位二进制的数值就被称为 “code point”,也就是码点,说白了就是每个字符的编号而已,这个和 ASCII 码的编号是一样的概念,只是换了个名字而已。就比如,码点 0x41 就表示大写字母 ‘A’。

最初的 ASCII 码是 7 位的,后来发展成了 8 位,因此 ASCII 码的范围就是 0x00 ~ 0xFF。Unicode 是 16 位的,范围就是 0x0000 ~ 0xFFFF,也就是四位十六进制表示这一个 Unicode 字符的,比如 “汉” 的 Unicode 码点是 Ox6C49。

Ps: 需要注意的一点是,这里用两个字节来表示一个 Unicode 字符,并不是说实际存储也是用两个字节来进行存储一个字符的。并不是这样的。在存储的时候,可以用大于两个字节的空间去存储它,就像在 32 位电脑上用四个字节去存储一个整数 1,尽管是用一位就够了。

3、UTF-8

UTF-8(Universal Character Set/Unicode Transformation Format,8 位元)是针对 Unicode 的一种可变长度字符编码。它可以用来表示 Unicode 标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理 ASCII 字符的软件无须或只进行少部分修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。

3.1、Unicode 码和 UTF-8 的关系

通过 ISO(国际标准化组织)这个组织的名字也看得出来,它是一个专门制定标准的组织,就例如著名的 ISO 网络七层模型,这网络七层模型就是 ISO 制定出来的网络通讯标准,但是呢,大家也知道,实际上我们真正网络的实现上,并没有完全套用那七层模型,而是我们熟知的 TCP/IP 的四层模型。这里就出现了刚提到的实现和制定的标准上的差异。

至于为什么会出现这样的差异问题,这就是理论和实践的不同导致的,虽然很多理论看起来说起来是十分完美的,但是真正运用到生活中的结果缺不得而知,我们知道时间是检验真理的唯一标准,UTF(Unicode Transformation Format,Unicode 转换格式) 就是这样的产物。

UTF-8 就是专门对 Unicode 这套理论标准的一种具体实现。UTF-8 是参照 Unicode 标注而做出来的真正能用于实际生活的一套东西。说白了就是:Unicode 是一套方案,是理论知识,而 UTF-8 是具体实现。而 Unicode 的实现也很多,UTF-8 是 Unicode的具体实现之一,此外还包括,UTF-16 和 UTF-32。

3.2、UTF-8 具体实现

Unicode 虽然能容纳上百万数量的字符 ,但它只是一个巨大的字符集而已,仅仅规定了每个符号的二进制代码表示,然鹅并没有制定具体的存储规则,因此它仅限于概念,没有具体落实到底该怎么去实现。因此到目前为止还只是纸上谈兵。这导致 Unicode 有不少问题,比如当用 3 个字节存储一个 Unicode 字符的时候,它同时也可以被理解为存储了 3 个大小为 1字节的ASCII码,这是具有二义性的。 另外,我们之前知道 ASCII 码只需要一个字节,但是,如果 Unicode 规定每个字符都用 3 个字节来存储的话,那岂不是活生生浪费了两个字节的空间?所有这些未经细化的问题都将导致 Unicode的 不一致性, 因此导致 Unicode 在很长一段时间内无法推广。

UTF 的出现,就解决了上述提到的 Unicode 问题,而 UTF-8 实现方式又是最通用和常见的一种方式了。因此我们在这里将介绍 UTF-8 的具体实现,让你真正认识到什么是 UTF-8.

UTF-8 最大的一个特征就是变长存储的编码方式。它可以使用1 ~ 4个字节去存储不同的字符,根据不同的字符选择最合适的字节长度去进行存储。这样就起到了合理利用存储空间的作用。

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

  1. 对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 Unicode 码。因此对于英语宇母, UTF-8 编码和 ASCII 码是相同的;
  2. 对于 n 字节的符号(n>1),第 一个字节的前 n 位都设为 1,第 n+1 位设为 0,后面字节的前两位一律设为 10(注意这里说的是二进制10)。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码.
3.3、UTF-8 具体实现的详细解读

一个字节的时候: UTF-8 遇到一个字节的时候,为了做到兼容 ASCII 码,它的做法就很干脆,就把最高位设为 0,后七位直接使用 ASCII码 编码规则来进行存储。这样做完美做到了兼容 ASCII 码;

image-20240122110906737

当大于一个字节的时候: 由于 UTF-8 编码是变长的,因此就出现了一个亟待解决的问题,就是,怎么知道当前的一个 UTF-8 编码到底占用几个字节空间?因此就必须得有一种方式来标记当前的 UTF-8 编码占用了多少个字节。

大于一个字节的时候,我们把第一个字节称为 “高字节”,其余的所有字节都称之为 “低字节”。

当此编码用几个字节存储,那么它的高字节的前几位就为 1,然后紧接着的一位设置为 0。其余所有低字节的高两位固定为 10。为了叙述方便,我们把高字节和低宇节中那些用以标识 UTF-8 特征的位(不能用于存储数据的位)暂称为标记位。如果一个 UTF-8 编码占用了 n 个字节,高字节的高 n 位就都是 1,第 n+1 位是 0。低字节的高位均以 10 开头。除了各字节高位的标记位之外的其他位才是真正存储数据的位,暂称为数据位。

3.4、问题 1 : 为什么第 n+1 位是 0 呢 ?

从上面我们知道,UTF-8 的高字节的决定了当前编码占据多少字节。在读取的时候是怎么确定当前编码占据多少字节的呢 ?就是从高字节的最高位开始读取,发现是当前位是 1,就加一个字节,那么,怎么知道高字节中的标记位在什么时候结束呢 ?我们也知道,数据位也是能存储1的,那么怎么知道在读取高字节的位数数值的时候,当前位是数据位还是标记位呢 ?那么,为了解决这个问题,最好的解决方法就是在标记位的所有 1 的后面紧跟着一个 0 就行了,在读取数值的时候,从最高位开始读取,当读取到第一个 0 的时候,就认定当前的标记位读取结束,这时候读取到多少个 1,就说明当前编码占用多少个字节。就此完美解决这个问题。

3.5、问题 2 : 为什么 2 字节及以上包括的 UTF-8 编码 ,低字节的高 2 位始终是固定的 10 呢 ?

我们上面提到过 UTF-8 会去兼容 ASCII 码,但是 UTF-8 的编码规则和 ASCII 不同,必须要特殊处理 ASCII 码。 任何编码在底层上都是二进制字节流 ,解码器在获得 1 字节的二进制数据时,如何知道这是 ASCII 码,还是 UTF-8 编码的高字节或低字节呢?所以 UTF-8 首先要做的是在二进制字节上必须与 ASCII 区分开来,即在这 1 字节数据上做标记,通过标记就知道这是 UTF-8编码还是 ASCII 码。ASCII 是单字节,2 字节以上的数据用 UTF-8 编码才有意义,否则 1 个字节就够用的话就直接用 ASCII 了。

ASCII 码范围是 0 ~ 127, 因此其最高位是 0,而 2 字节以上的 UTF-8 编码其高字节最高位是 1,这样高字节己经可以和 ASCII 区分了,那么低字节如何和 ASCII 区分呢?你可能会说,只要 UTF-8 编码中低字节最高位也不为 0 就可以了,即只要是 1 就行 。

其实不然,仅仅最高位为 1 是区分不了的。因为如果只要求最高位是 1,那么就有可能和高字节混淆,比如二进制 11001101,这是 UTF-8 的高字节还是低字节?

没有办法区分。那么,最不可能成为 UTF-8 高字节标记位的就是 10,我们假设 10 是高字节的标记位,按照 UTF-8 编码规则,说明 UTF-8 编码只用了 1字节,显然这是矛盾的,因为在 UTF-8 中 1 字节的字符用其兼容的 ASCII 码表示,最高位是 0,而不是 1,因此 UTF-8 至少要 2 字节以上才有意义,1 字节纯粹是为了兼容 ASCII 码,所以采用 10 作为低字节的标识位才是最合适的。既然标识位 10 只能出现在低字节的高 2 位 ,那么反过来说, UTF-8 编码中以 10 开头的都是低字节。低字节有了这个特性便具备了校验的能力,比如读取 UTF-8编 码的高字节后,确保后面的低字节必须以 10 开头才是正确的 UTF-8 编码。

结语: 我们现在已经知道了,Unicode 和 UTF-8到底是什么了。并且我们也能够知道,当当前的 UTF-8 编码是两个字节的时候,实际上,用于存储数据的位数是没有满满的两个字节(16位),而是 11 位。为什么呢?因为高字节的前三位110是标志位,低字节的前两位 10 是标志位,因此总共的标志位就有 5 位,剩余的存储为只有11位了。同理,我们也能通过存储占用的空间大小来反推出 UTF-8 编码占据多少字节。

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

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

相关文章

线下教育招生营销短信群发时这几点很重要

线下教育招生营销短信群发时,以下几点非常重要,可以帮助教育机构更有效地进行招生营销: 一、明确目标受众 1.确定目标学生群体:了解你的机构主要服务于哪个年龄段、需求和兴趣的学生,以便更有针对性地编写短信内容。…

LeetCode热题100 Day1——双指针

双指针 移动零11. 盛最多水的容器 移动零 思路: 双指针i,j,j指针遍历数组,i指针存放非0元素。遍历结束后,i指针及其后面的一定是0,就再将空出来的位置设置为0 移动零 class Solution {public void moveZeroes(int[] …

942. 增减字符串匹配 - 力扣

1. 题目 由范围 [0,n] 内所有整数组成的 n 1 个整数的排列序列可以表示为长度为 n 的字符串 s &#xff0c;其中: 如果 perm[i] < perm[i 1] &#xff0c;那么 s[i] I 如果 perm[i] > perm[i 1] &#xff0c;那么 s[i] D 给定一个字符串 s &#xff0c;重构排列 pe…

Linux搭建PHP下的RabbitMQ环境(php-amqp/rabbitmq-c/erlang)

本文演示环境 Red Hat 11.2.1-9gcc (GCC) 11.2.1 20220127OpenSSL v1.1.0PHP 7.1 安装erlang erlang和RabbitMQ有版本对应关系Erlang Version Requirements&#xff0c;需要选择正确的版本。 本文以erlang 26和RabbitMQ 3.13.2为例。 erlang下载地址 下载包上传服务器后&a…

Ubuntu20.04升级到22.04之后出现的问题

项目场景&#xff1a; 之前一致使用的是Ubuntu20.04&#xff0c;虽然丑了点&#xff0c;但是用着没什么问题&#xff0c;最近没能按捺住好奇心&#xff0c;升级到了22.04&#xff0c;升级后颜值有所提高&#xff0c;但是也带来了一些问题。 从20.04升级到22.04&#xff0c;起始…

Cobaltstrike渗透测试框架

Cobaltstrike简介 cobalt strike&#xff08;简称CS&#xff09;是一款团队作战渗透测试神器&#xff0c;分为客户端及服务端&#xff0c;一个服务端可以对应多个客户 端&#xff0c;一个客户端可以连接多个服务端&#xff0c;可被团队进行分布式协团操作. 和MSF关系 metas…

pdf只要其中一页 pdf只要第一页怎么办 pdf只要前几页怎么弄

在现代办公环境中&#xff0c;PDF文件已经成为我们日常工作中不可或缺的一部分。然而&#xff0c;有时我们可能只需要PDF文件中的某一页&#xff0c;而不是整个文件。这时&#xff0c;我们该如何操作才能只获取所需的那一页呢&#xff1f;本文将详细操作方法&#xff0c;帮助大…

【ai】livekit服务本地开发模式及example app信令交互详细流程

文档要安装git lfs 下载当前最新版本1.6.1 windows版本&#xff1a;启动dev模式 服务器启动 (.venv) PS D:\XTRANS\pythonProject\LIVEKIT> cd .\livekit_release\ (.venv) PS D:\XTRANS\pythonProject\LIVEKIT\livekit_release> lsDirectory: D:\XTRANS\pythonProject\L…

CATIA二次开发VBA入门(3)——vb语言基础,可视化编程基础,消息框等

目录 引出VBA与VB的关系和区别vb基础关于什么时候用set字符串函数数学&#xff1a;三角函数&#xff0c;不等于&#xff0c;随机数日期、脚本、空格数组 顺序、选择、循环可视化编程基础按钮文字输入框的输入窗口控件全局变量 vb基础进阶msgbox详解背景颜色按钮能否点击插入图片…

python-使用API

python-使用API 使用github的api-即url地址请求数据 https://api.github.com/search/repositories?qlanguage:python&sortstars #这个调用返回GitHub当前托管了多少个Python项目&#xff0c;还有有关最受欢迎的Python仓库的信息。在浏览器中输入上面地址可以看到该接口&…

C++第二十一弹---vector深度剖析及模拟实现(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、基本结构 2、默认成员函数 2.1、构造函数 2.2、析构函数 2.3、拷贝构造函数 2.3、赋值操作符重载 3、数据访问 4、迭代器获取 总结 …

Redis篇 String的基本命令

String基本命令 一.setnx,setex,psetex二. 增加删除命令三.append,setrange,getrange,strlen命令1.append2.setrange3.strlen4.getrange 四.String的内部编码方式 一.setnx,setex,psetex setex和psetex设置过期时间 setex设置的过期时间是秒级 psetex设置的过期时间是毫秒级 二…

【错误记录】HarmonyOS 运行报错 ( Failure[MSG_ERR_INSTALL_FAILED_VERIFY_APP_PKCS7_FAIL] )

文章目录 一、报错信息二、问题分析二、解决方案 一、报错信息 在 DevEco Studio 中 , 运行程序 , 编译时正常编译 , 但是在真机运行时 , 报如下错误 , 核心报错信息是 " Failure[MSG_ERR_INSTALL_FAILED_VERIFY_APP_PKCS7_FAIL] " ; 完整报错信息 : 05/29 10:58:55…

探索Django 5: 从零开始,打造你的第一个Web应用

今天我们将一起探索 Django 5&#xff0c;一个备受开发者喜爱的 Python Web 框架。我们会了解 Django 5 的简介&#xff0c;新特性&#xff0c;如何安装 Django&#xff0c;以及用 Django 编写一个简单的 “Hello, World” 网站。最后&#xff0c;我会推荐一本与 Django 5 相关…

工控一体机10.1寸显示器电容触摸屏(YA07JK)产品规格说明书

如果您对工控一体机有任何疑问或需求&#xff0c;或者对如何集成工控一体机到您的业务感兴趣&#xff0c;可移步控芯捷科技。 一、硬件功能介绍 1.1 YA07JK介绍 YA07JK 是我公司推出的一款新型安卓屏&#xff0c;使用电容触摸屏。4 核 Cortex-A7 架构&#xff0c;主频1.2GHz …

React-Redux结合@Reduxjs/Toolkit实现函数组件化(数据持久化,刷新页面数据不丢)

函数式组件和类式组件的优缺点儿 函数组件&#xff08;Function Component&#xff09;和类组件&#xff08;Class Component&#xff09;是React中的两种定义组件的方式。函数组件是以一个函数的方式定义组件&#xff0c;而类组件则是以ES6的类继承React.Component来定义组件…

后端企业级开发之yaml数据序列化格式文件详解2024

yaml格式 数据格式 yaml 是一种数据序列化的格式 容易阅读 容易与脚本语言交互 以数据为核心 重数据轻格式 我们要知道他怎么书写 大小写敏感 属性层级关系使用多行描述 每行结尾使用冒号结束 使用缩进表示层级关系 同层级左侧对其 只运行使用空格 属性前面添加空格 #表…

《Ai企业知识库》-rasa-初步使用

根据上面的环境准备之后&#xff1a; 《Ai企业知识库》-模型实践-rasa开源学习框架-搭建简易机器人-环境准备(针对windows)-02-CSDN博客 基础的使用&#xff1a; rasa项目初始化&#xff1a; rasa init 首先进入目标文件夹 在dos窗口&#xff08;目标文件夹下&#xff09…

智能合约革命:Web3引领智能化商业的未来

随着区块链技术的日益成熟和普及&#xff0c;智能合约作为其重要应用之一&#xff0c;正在逐渐改变着商业世界的面貌。Web3作为下一代互联网的代表&#xff0c;以其去中心化、加密安全的特性&#xff0c;为智能合约的发展提供了无限可能&#xff0c;将智能合约应用于商业领域的…

海云安两大金融案例入编行业典范,七大安全领域实力登榜《2024中国金融网络安全全景图》

近日&#xff0c;数说安全与《中国信息安全》杂志联合编写并发布了《2024年中国金融行业网络安全研究报告》&#xff08;以下简称报告&#xff09;、《2024年中国金融行业网络安全案例集》&#xff08;以下简称案例集&#xff09;、《2024年中国金融行业网络安全市场全景图》&a…