• UTF-8编码及非英文字符的处理与显示


    char类型只包含1个字节的存储空间,而1个字节最多能表达256种不同的值。如果只表达英文字符及其标点符号,1个字节足够。但其它文字,比如中文,其“字符”有数万之多。在编码其它语言文字时,可能会使用到不同的多字节编码方案。

    本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
    叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
    1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
    2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
    3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频

    1. 文本编码与解码

    计算机是二进制的,它的文件和内存严格地说,只能存储和处理比特流,每个比特对应二进制的1位。由于这些二进制位按8位一组被分隔成字节,我们也可以认为计算机只能存储和处理字节流,用大白话说就是一个接一个的字节。

    所以,当我们把由多个字符构成的文章存储到计算机里的时候,存入到内存或者硬盘的并不是文字本身,而是这些文字字符的对应编码。我们以ASCII码为例为说明相关过程。ASCII码是所谓美国标准信息交换代码,它用一个字节来表示一个字符。一个字节有8位,共256种组合,用来表示英文字符、数字及标点绰绰有余。

    ASCII码的完整码表请见: 美国信息交换标准交换代码表 - Python,C/C++ Club (codelearn.club)

    为便于讨论,我们在Windows下用记事本编辑了如下内容的文件,并保存为hw.txt。
    在这里插入图片描述
    查看hw.txt的文件属性,可见该文件事实上占据了11个字节的空间。
    在这里插入图片描述
    回顾hw.txt的文件内容,其中的”Hello World”连同其中的空格一起,正好11个字符。
    image-20221101175008387
    注意:000000 000013表示序号,不是文件的构成内容。

    Windows命令行下,使用如上图所述的od命令可以查看文件hw.txt的原始内容,其内的11个字节的值用16进制表示出来就是:

    48 65 6C 6C 6F 20 57 6F 72 6C 64
    
    • 1

    其中,48在ASCII码里对应’H’,65对应’e’,20对应空格,64对应’d’…

    文本编码

    将文本存储至计算机内时,需要先把文本中的字符逐一转换成对应的编码,这一过程被称为”文本编码“。比如,文本”Hello World”被编码成字节流”48 65 6C 6C 6F 20 57 6F 72 6C 64“。

    文本解码

    对于Windows记事本而言,文件hw.txt就是包含11个字节的字节流,需要将这11个字节按照码表映射至文本,再显示出来,这一过程被称为”文本解码“。比如,字节流”48 65 6C 6C 6F 20 57 6F 72 6C 64“被转换成”Hello World”。

    编码方案

    同一文字符号,在不同的编码方案内,其对应的字节或字节序列很可能不同。

    • ASCII码使用一个字节表示一个字符,而1个字节仅有8个比特,256种组合,因此,ASCII码只能表示英文字母、数字及符号。
    • GB2312-80(汉语国标)使用双字节来表示一个汉字符号,同时,为了兼容英文,也用单字节来表示英文字符。理论上,GB2312-80可以较好地支持同一个文件内的中英文混合表达。但随着国际交流的日益频繁,在同一个网页或者文档里, 英、法、日、中、泰、韩等多国语言交替使用的场景屡见不鲜,此时,GB2312-80就不够用了。 后来国家又出手搞了GB18030… 但事实上未获得广泛应用。
        
      为了促进世界大同,有人弄出了Unicode®,这种编码方案可以在同一文档/网页内容纳多国语言没有歧义地混合使用。

    2. Unicode®

    粗略地理解,Unicode就是一张表,这张表将世界上”所有“的文字字符,甚至一些表情符号(emoji表情)对应成互不相同的整数。Unicode®自发明以来,一直在不断修订中,以收录”新“的语言符号。至2022年9月13日止,Unicode® 15.0.0总共收录了149,186个字符。Unicode的表太长,下表给出了其中的几个示例。

    表1 Unicode编码示例

    符号编码(整数,16进制)说明
    B0042英文字符
    Ê00CA
    ڣ06A3阿拉伯语字符
    0975未知语言字符
    1170韩语符号
    222B数学符号之积分
    26FA帐篷
    3056日语假名
    4EBA汉字

    完整的Unicode®表格可以通过下述链接查询:https://unicode-table.com/en/

    Unicode® 15.0.0的标准原文见:https://www.unicode.org/versions/Unicode15.0.0/

    3. UTF-8

    UTF-8可以认为是Unicode的一种实施方案,通过UTF-8可以把一个字符对应的Unicode编码(一个整数)转换成一个字节序列,这个字节序列可能包含1个、2个、3个或者4个字节。

    表2 Unicode编码与UTF-8的转换关系

    Unicode编码(16进制)UTF-8字节序列说明
    000000 ~ 00007F0xxxxxxx单字节, 含7个x
    000080 ~ 0007FF110xxxxx 10xxxxxx2字节,含11个x
    000800 ~ 00FFFF1110xxxx 10xxxxxx 10xxxxxx3字节, 含16个x
    010000 ~ 10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx4字节, 含21个x

    转换举例

    • 对于英文字母、数字及英文符号,其Unicode编码与ASCII是一致的, 其值≤0x7F,按上表的规则,仍使用单字节编码。比如,’B’的Unicode编码为000042₁₆ ,转换成7位二进制即为1000010₂ ,逐一替换上表第1行中的7个x,即为01000010₂ ,仍是42₁₆ ,与’B’的ASCII码值完全相同。
    • 对于阿拉伯母字符’ڣ’,其Unicode编码为06A3₁₆ ,其值满足上表第2行的条件,按规则应使用2字节编码。06A3₁₆ 转换成11位二进制即为11010100011₂ ,逐一替代上表第2行中的11个x,即为11011010 10100011₂ ,按16进制表达即为DA A3₁₆ 。
    • 对于汉字’人’,其Unicode编码为4EBA₁₆ ,其值符合上表第3行的条件,按规则应使用3字节编码。4EBA₁₆ 转换成16位二进制即为01001110 10111010₂ ,逐一替代上表第3行中的16个x,即为11100100 10111010 10111010₂ ,按16进制表达即为E4 BA BA₁₆ 。

    3. UTF-8编码示例

    我们使用Windows记事本编辑了一个”多国语言文件”,其中包含英文字母“B”,阿拉伯母字母“ڣ”,以及汉语的“人”,然后按UTF-8编码保存为文件mixed.txt。
    在这里插入图片描述
    注意保存时选择UTF-8编码。
    在这里插入图片描述
    查看mixed.txt文件属性,发现其尺寸为6个字节。
    在这里插入图片描述
    再次使用od命令查看文件mixed.txt的原始内容,结果如下:
    在这里插入图片描述
    注意:000000, 000006是序号信息,不是文件的构成部分。

    其中的”42 DA A3 E4 BA BA”与前述分析完全相同。编码程序完全按照上述UTF-8规则将文字”Bڣ人”转换为字节序列”42 DA A3 E4 BA BA”,然后把这个字节序列共6个字节写入文件mixed.txt。

    4. UTF-8的模拟解码

    当我们用记事本将文件mixed.txt中的原始内容读出时,其就是由6个字节构成的字节序列:42 DA A3 E4 BA BA₁₆ 。 作为一个文字编辑软件,记事本需要通过UTF-8解码将上述字节序列查表转换成”Bڣ人”,然后再将其显示出来。字符的显示过程涉及绘图、字体等内容,此处略去不提。

    我们可以假想出记事本软件内部的解码程序的执行过程:

    • 解码程序从前至后逐一扫描字节序列,首先遇到42₁₆ ,即01000010₂,该字节的最高位为0,根据表2,该字节为1字节编码,其单独表示一个Unicode字符,按表2第1行的规则从中取得后7个比特,其值仍为42₁₆ ,查Unicode表,即得英文字符’B’。
    • 解码程序继续扫描,得DA₁₆ ,即11011010₂,其高3位为110,根据表2,该字节连同后面的A3合为一个2字节编码,按表2第2行的规则从中抽取11个比特,得11010100011₂,即06A3₁₆ ,查Unicode表,即得阿拉伯语字符‘ڣ’。
    • 解码程序继续扫描,得E4₁₆ ,即11100100₂,其高4位为1110,根据表2,该字节连同后面的BA BA合为一个3字节编码,按表2第3行的规则从中抽取16个比特,得01001110 10111010₂,即4EBA₁₆ ,查Unicode表,即得汉字’人’。
    • 字节序列结束,解码程序终止。

    从上述解码过程,读者不难看出,UTF-8的编码是没有歧义的,即特定的字节序列与特定的文本内容一一对应。在以汉字为主的文档里,使用UTF-8编码,一个汉字需要3个字节来表达,而使用GB2312-80,一个汉字只需要2个字节来表达。相较于后者,UTF-8编码的文 档需要占据更多的存储空间以及网络带宽。

    5. UTF-16, UTF-32

    作者觉得没什么意思,UTF-8现在是主流,读者在安装Linux,设计网页时,如果选用UTF-8编码,是最安全的。

    事实上,除了UTF-8,GB2312-80,ASCII,世界还有很多很多乱七八糟的编码方案…

    6. 为什么会乱码

    在这里插入图片描述
    读者或许在程序开发的过程中看到过如上图所示的乱码现象。所谓乱码,本质是文本编码与文本解码发生了错位,如果把一个GB2312-80编码的文档按照UTF-8来进行解码,自然会发生错误,形成所谓“乱码”。

    为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!

    简洁的C及C++
    由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造
    Python编程基础及应用
    由编程界擅长教书,教书界特能编程的海洋饼干叔叔打造

    如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。

    Python编程基础及应用

    Python编程基础及应用实验教程
    在这里插入图片描述

  • 相关阅读:
    银行互联网类业务基于分布式存储的架构设计与实施运维分享
    MySQL报错:unknown collation: ‘utf8mb4_0900_ai_ci‘
    基于学生成绩管理系统(附源代码及数据库)
    2024Java springboot mybatis-flex 根据数据表时间开启定时任务
    基于MATLAB的风力光伏发电模型模拟以及遗传算法求解混合发电系统最优配置
    4款实用的黑科技软件,白嫖党最爱,功能强大到离谱
    数据分析——对比思维、A/B test
    使用免费开源软件 Blender 编辑视频
    C#---第22:Newtonsoft中json/array的解析、创建、SelectToken(获取指定values)方法
    Python数学基础2
  • 原文地址:https://blog.csdn.net/SeaBiscuitUncle/article/details/127662892