一文读懂字符编码从此解决乱码问题

2024-03-15 13:30

本文主要是介绍一文读懂字符编码从此解决乱码问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、 引入
  • 二、 知识储备
    • 2.1 三大核心硬件
    • 2.2 文本编辑器读取文件内容的流程
    • 2.3 python解释器执行文件的流程
    • 2.4 总结
  • 三、字符编码介绍
    • 3.1 什么是字符编码?
    • 3.2 字符编码表的发展史 (了解)
      • 3.2.1 阶段一:一家独大阶段
      • 3.2.2 阶段二:诸侯割据、天下大乱
      • 3.2.3 阶段三:分久必合
    • 3.3 编码与解码
    • 3.4 utf-8的由来
  • 四、 字符编码的应用
    • 4.1 文本编辑器nodpad++存取文本文件
      • 1. 存乱了
      • 2. 取乱了
    • 4.2 python解释器执行文件的前两个阶段
    • 4.3 python解释器执行文件的第三个阶段

一、 引入


​ 字符串类型、文本文件的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题。
​ 字符编码这个知识点的典型特征就是理论多、结论少,但对于开发而言只需要记住结论即可。


二、 知识储备

2.1 三大核心硬件

所有软件都是运行硬件之上的,与运行软件相关的三大核心硬件为cpu、内存、硬盘,我们需要明确三点

  1. 软件运行前,软件的代码及其相关数据都是存放于硬盘中的

  2. 任何软件的启动都是将数据从硬盘中读入内存,然后cpu从内存中取出指令并执行

  3. 软件运行过程中产生的数据最先都是存放于内存中的,若想永久保存软件产生的数据,则需要将数据由内存写入硬盘

在这里插入图片描述

2.2 文本编辑器读取文件内容的流程

  • 阶段1、启动一个文件编辑器(文本编辑器如nodepad++,pycharm,word)
  • 阶段2、文件编辑器会将文件内容从硬盘读入内存
  • 阶段3、文本编辑器会将刚刚读入内存中的内容显示到屏幕上

2.3 python解释器执行文件的流程

以python test.py为例,执行流程如下

  • 阶段1、启动python解释器,此时就相当于启动了一个文本编辑器
  • 阶段2、python解释器相当于文本编辑器,从硬盘上将test.py的内容读入到内存中
  • 阶段3、python解释器解释执行刚刚读入的内存的内容,开始识别python语法

2.4 总结

python解释器与文本编辑的异同如下

  1. 相同点:前两个阶段二者完全一致,都是将硬盘中文件的内容读入内存,详解如下
    python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样

  2. 不同点:在阶段3时,针对内存中读入的内容处理方式不同,详解如下
    文本编辑器将文件内容读入内存后,是为了显示或者编辑,根本不去理会python的语法,而python解释器将文件
    内容读入内存后,是为了执行python代码、会识别python语法)


三、字符编码介绍

3.1 什么是字符编码?

人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等,而计算机只能识别二进制数,详解如下:

二进制数即由0和1组成的数字,例如010010101010。计算机是基于电工作的,电的特性即高低电平,人类从逻辑层面将高电平对应为数字1,低电平对应为数字0,这直接决定了计算机可以识别的是由0和1组成的数字毫无疑问,由人类的字符到计算机中的数字,必须经历一个过程,如下
在这里插入图片描述
翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一对应的关系。
字符编码中的编码指的是翻译或者转换的意思,即将人能理解的字符翻译成计算机能识别的数字

3.2 字符编码表的发展史 (了解)

字符编码的发展经历了三个重要的阶段,如下

3.2.1 阶段一:一家独大阶段

现代计算机起源于美国,所以最先考虑仅仅是让计算机识别英文字符,于是诞生了ASCII表
在这里插入图片描述

ASCII表的特点:
1、只有英文字符与数字的一一对应关系
2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符

3.2.2 阶段二:诸侯割据、天下大乱

为了让计算机能够识别中文和英文,中国人定制了GBK

# GBK表的特点:
1、只有中文字符、英文字符与数字的一一对应关系
2、一个英文字符对应1Bytes一个中文字符对应2Bytes   补充说明:1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符

每个国家都各自的字符,为让计算机能够识别自己国家的字符外加英文字符,各个国家都制定了自己的字符编码表

# Shift_JIS表的特点:1、只有日文字符、英文字符与数字的一一对应关系# Euc-kr表的特点:1、只有韩文字符、英文字符与数字的一一对应关系

此时,美国人用的计算机里使用字符编码标准是ASCII、中国人用的计算机里使用字符编码标准是GBK、日本人用的计算机里使用字符编码标准是Shift_JIS,如下图所示,
在这里插入图片描述

字符编码发展到了这个阶段,可以用一句话概括:诸侯割据、天下大乱,详解如下
图1中,文本编辑存取文件的原理如下:

文本文件内容全都为字符,无论存取都是涉及到字符编码问题
#1、存文本文件
人类通过文本编辑器输入的字符会被转化成ASCII格式的二进制存放于内存中,如果需要永久保存,
则直接将内存中的ASCII格式的二进制写入硬盘
#2、读文本文件
直接将硬盘中的ASCII格式的二进制读入内存,然后通过ASCII表反解成英文字符

图2图3都是相同的过程,此时无论是存还是取由于采用的字符编码表一样,所以肯定不会出现乱码问题,但问题是在美国人用的计算机里只能输入英文字符,而在中国人用的计算机里只能输入中文字符和英文字符…,毫无疑问我们希望计算机允许我们输入万国字符均可识别、不乱码,而现阶段计算机采用的字符编码ASCII、GBK、Shift_JIS都无法识别万国字符,所以我们必须定制一个兼容万国字符的编码表,请看阶段三

3.2.3 阶段三:分久必合

在这里插入图片描述

unicode于1990年开始研发,1994年正式公布,具备两大特点:

  1. 存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符

  2. 与传统的字符编码的二进制数都有对应关系,详解如下:

很多地方或老的系统、应用软件仍会采用各种各样传统的编码,这是历史遗留问题。此处需要强调:软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将它们全都正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对应的映射/转换关系,这就是unicode的第二大特点产生的缘由
在这里插入图片描述

文本编辑器输入任何字符都是最新存在于内存中,是unicode编码的,存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符

# 英文字符可以被ASCII识别
英文字符--->unciode格式的数字--->ASCII格式的数字# 中文字符、英文字符可以被GBK识别
中文字符、英文字符--->unicode格式的数字--->gbk格式的数字# 日文字符、英文字符可以被shift-JIS识别
日文字符、英文字符--->unicode格式的数字--->shift-JIS格式的数字

3.3 编码与解码

由字符转换成内存中的unicode,以及由unicode转换成其他编码的过程,都称为编码encode
在这里插入图片描述

由内存中的unicode转换成字符,以及由其他编码转换成unicode的过程,都称为解码decode
在这里插入图片描述

在诸多文件类型中,只有文本文件的内存是由字符组成的,因而文本文件的存取也涉及到字符编码的问题

3.4 utf-8的由来

注意:如果保存到硬盘的是GBK格式二进制,当初用户输入的字符只能是中文或英文,同理如果保存到硬盘的是Shift_JIS格式二进制,当初用户输入的字符只能是日文或英文……如果我们输入的字符中包含多国字符,那么该如何处理?

#多国字符—√—》内存(unicode格式的二进制)——X—》硬盘(GBK格式的二进制)#多国字符—√—》内存(unicode格式的二进制)——X—》硬盘(Shift_JIS格式的二进制)#多国字符—√—》内存(unicode格式的二进制)——√—》硬盘(???格式的二进制)

理论上是可以将内存中unicode格式的二进制直接存放于硬盘中的,但由于unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式即utf-8(全称Unicode Transformation Format,即unicode的转换格式)

# 多国字符——》内存(unicode格式的二进制)———》硬盘(utf-8格式的二进制)

在这里插入图片描述

那为何在内存中不直接使用utf-8呢?
utf-8是针对Unicode的可变长度字符编码:一个英文字符占1Bytes,一个中文字符占3Bytes,生僻字用更多的Bytes存储
unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,等过去几十年,所有老编码的文件都淘汰掉之后,会出现一个令人开心的场景,即硬盘里放的都是utf-8格式,此时unicode便可以退出历史舞台,内存里也改用utf-8,天下重新归于统一


四、 字符编码的应用

我们学习字符编码就是为了存取字符时不发生乱码问题:

1、内存中固定使用unicode无论输入任何字符都不会发生乱码2、我们能够修改的是存/取硬盘的编码方式,如果编码设置不正确将会出现乱码问题。
乱码问题分为两种:存乱了,读乱了2.1 存乱了:如果用户输入的内容中包含中文和日文字符,如果单纯以shift_JIS存,
日文可以正常写入硬盘,而由于中文字符在shift_jis中没有找到对应关系而导致存乱了2.2 读乱了:如果硬盘中的数据是shift_JIS格式存储的,采GBK格式读入内存就读乱了

总结:

  1. 保证存的时候不乱:在由内存写入硬盘时,必须将编码格式设置为支持所输入字符的编码格式
  2. 保证取的时候不乱:在由硬盘读入内存时,必须采用与写入硬盘时相同的编码格式

4.1 文本编辑器nodpad++存取文本文件

文本编辑器存取的都是文本文件,而文本文件中包含的内容全为字符,所以存取文本文件都涉及到字符编码的问题。

1. 存乱了

在这里插入图片描述

文本中既有中文也有韩文,如果用韩文编码方式保存文件时候,如果再次打开文件,中文是肯定会乱码的,这叫存乱了。

在这里插入图片描述

2. 取乱了

现在,我们用gb2321格式保存一段中文
在这里插入图片描述
我们用ANSI格式打开,就会出现乱码,因为存与取的编码方式不一致
在这里插入图片描述
在以gb2312格式打开,又能恢复正常
在这里插入图片描述
存乱了对文文件是不可逆的,数据已经被破坏了,取乱了只要以相同的编码取就可解决乱码问题

4.2 python解释器执行文件的前两个阶段

执行py文件的前两个阶段就是python解释器读文本文件的过程,与文本编辑读文本文件的前两个阶段没人任何区别,要保证读不乱码,则必须将python解释器读文件时采用的编码方式设置为文件当初写入硬盘时的编码格式,如果没有设置,python解释器则才用默认的编码方式,在python3中默认为utf-8,在python2中默认为ASCII,我们可以通过指定文件头来修改默认的编码
在文件首行写入包含#号在内的以下内容

# coding: 当初文件写入硬盘时采用的编码格式

解释器会先用默认的编码方式读取文件的首行内容,由于首行是纯英文组成,而任何编码方式都可以识别英文字符。

4.3 python解释器执行文件的第三个阶段

设置文件头的作用是保证运行python程序的前两个阶段不乱码,经过前两个阶段后py文件的内容都会以unicode格式存放于内存中。
在经历第三个阶段时开始识别python语法,当遇到特定的语法name = ‘上’(代码本身也都全都是unicode格式存的)时,需要申请内存空间来存储字符串’上’,这就又涉及到应该以什么编码存储‘上’的问题了。
在Python3中,字符串类的值都是使用unicode格式来存储
由于Python2的盛行是早于unicode的,因此在Python2中是按照文件头指定的编码来存储字符串类型的值的(如果文件头中没有指定编码,那么解释器会按照它自己默认的编码方式来存储‘上’),所以,这就有可能导致乱码问题

# coding:utf-8
x = '上' # x的值为untf-8格式的二进制
print(x) # 打印操作是将x的值,即utf-8格式的二进制交给终端,当终端收到后发现并不是unicode(只有unicode才与字符有对应关系),
所以终端会执行操作:utf-8二进制---解码-->unicode格式的二进制,解码的过程终端会采用自己默认的编码,
而在pycharm的终端默认编码为utf-8、windows下的cmd终端的默认编码为gbk,所以该打印操作在pycharm中显示正常,
而在windows下的cmd中则乱码# 在windows下的cmd中运行效果如下
C:\Users\Administrator>python2 E:\aaa.py
涓

python2后推出了一种补救措施,就是在字符串类型前加u,则会将字符串类型强制存储unicode,这就与python3保持一致了,对于unicode格式无论丢给任何终端进行打印,都可以直接对应字符不会出现乱码问题

# coding:utf-8
x = u'上' # 即便文件头为utf-8,x的值依然存成unicode

4.4 字符串encode编码与decode解码的使用

# 1、unicode格式------编码encode-------->其它编码格式
>>> x='上' # 在python3在'上'被存成unicode
>>> res=x.encode('utf-8')
>>> res,type(res) # unicode编码成了utf-8格式,而编码的结果为bytes类型,可以当作直接当作二进制去使用
(b'\xe4\xb8\x8a', <class 'bytes'>)# 2、其它编码格式------解码decode-------->unicode格式
>>> res.decode('utf-8') 
'上'

4.5 总结

分析过程x="上"内存
上-------翻译-----0101010
上《----翻译《-----0101010字符编码表就是一张字符与数字对应关系的表a-00
b-01
c-10
d-11ASCII表:1、只支持英文字符串2、采用8位二进制数对应一个英文字符串GBK表:1、支持英文字符、中文字符2、采用8位(8bit=1Bytes)二进制数对应一个英文字符串采用16位(16bit=2Bytes)二进制数对应一个中文字符串unicode(内存中统一使用unicode):1、兼容万国字符与万国字符都有对应关系2、采用16位(16bit=2Bytes)二进制数对应一个中文字符串个别生僻会采用4Bytes、8Bytesunicode表:内存人类的字符---------unicode格式的数字----------|                     ||                     ||硬盘                    |||                     ||                     |GBK格式的二进制       Shift-JIS格式的二进制老的字符编码都可以转换成unicode,但是不能通过unicode互转utf-8:英文->1Bytes汉字->3Bytes结论:1、内存固定使用unicode,我们可以改变的是存入硬盘采用格式英文+汉字-》unicode-》gbk英文+日文-》unicode-》shift-jis万国字符》-unicode-》utf-82、文本文件存取乱码问题存乱了:解决方法是,编码格式应该设置成支持文件内字符串的格式取乱了:解决方法是,文件是以什么编码格式存如硬盘的,就应该以什么编码格式读入内存3、python解释器默认读文件的编码python3默认:utf-8python2默认:ASCII指定文件头修改默认的编码:在py文件的首行写:#coding:gbk4、保证运行python程序前两个阶段不乱码的核心法则:指定文件头# coding:文件当初存入硬盘时所采用的编码格式5、python3的str类型默认直接存成unicode格式,无论如何都不会乱码保证python2的str类型不乱码x=u'上'6、了解python2解释器有两种字符串类型:str、unicode# str类型x='上' # 字符串值会按照文件头指定的编码格式存入变量值的内存空间# unicode类型x=u'上' # 强制存成unicode

这篇关于一文读懂字符编码从此解决乱码问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812136

相关文章

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

qt5cored.dll报错怎么解决? 电脑qt5cored.dll文件丢失修复技巧

《qt5cored.dll报错怎么解决?电脑qt5cored.dll文件丢失修复技巧》在进行软件安装或运行程序时,有时会遇到由于找不到qt5core.dll,无法继续执行代码,这个问题可能是由于该文... 遇到qt5cored.dll文件错误时,可能会导致基于 Qt 开发的应用程序无法正常运行或启动。这种错

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

一文全面详解Python变量作用域

《一文全面详解Python变量作用域》变量作用域是Python中非常重要的概念,它决定了在哪里可以访问变量,下面我将用通俗易懂的方式,结合代码示例和图表,带你全面了解Python变量作用域,需要的朋友... 目录一、什么是变量作用域?二、python的四种作用域作用域查找顺序图示三、各作用域详解1. 局部作

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

关于跨域无效的问题及解决(java后端方案)

《关于跨域无效的问题及解决(java后端方案)》:本文主要介绍关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录通用后端跨域方法1、@CrossOrigin 注解2、springboot2.0 实现WebMvcConfig

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2