Python学习手册第37章Unicode和字节串解读部分一 学习记录

news/2024/9/23 21:50:29/

第37章 unicode和字节串

字节串: py中用于表示二进制数据的数据类型。 它是一系列 字节 的序列,每个字节是一个0-255之间的整数。 字节串通常用于处理文件、网络通信等涉及二进制数据的场景。
例如将字符串编码为字节串,
s = '你好,世界'
bytes_s = s.encode('utf-8') #将字符串编码为utf-8字节串
b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c'
b前缀表示这是一个字节串。 第二,默认就是utf-8编码,可省略utf-8
s1 = 'hello'
s1.encode() # 得到b'hello'
所以py的二进制字节串尽量用字母表示,不能表示了再用十六进制。
每个字节是一个0-255之间的整数。

而py3的str字符串就是基于unicode的,可以包含任何unicode字符,字符串内部都是Unicode码点,
s = '你好,世界'
print(s)

转换关系:
用encode()方法将字符串转换为字节串,
用decode()方法将字节串转换回字符串。
b = 'hello,world'.encode()
s = b.decode()

Unicode和字节串是处理文本数据的两种不同方式(字节串还可以表示其它二进制数据,如图片、音频、数字)。
在Python 3中,默认的字符串类型就是Unicode字符串,也称为str类型。Unicode字符串可以包含任何Unicode字符,包括各种语言的字符和特殊符号。
字节串是二进制数据的表示形式,其类型为bytes。字节串通常用于处理非文本数据,如文件内容、网络数据等。

创建一个字节对象,
data = bytes([0x01,0x02,0x03,0x04])
file = open('example.bin', 'wb')
file.write(data)

【以上来自文心一言3.5, 一步一步地接近解了!】
关于操作系统的字符编码,
操作系统的字符编码主要指的是在操作系统层面上,如何将字符集中的字符映射为特定的二进制序列。【其实无论c++还是python,说系统编码不是指操作系统,而是指编译器(或解释器)的字符编码方案。 windows操作系统的终端程序是gbk的(中文系统上),通常说的windows操作系统编码是utf-16,是指哪里?
Windows操作系统在其内部处理字符时主要使用的是UTF-16编码,特别是从Windows NT开始。UTF-16(Unicode Transformation Format-16 bits)是一种可变长度的Unicode字符编码,它使用16位(2字节)来表示大部分常用的字符,但对于一些不常用的字符,它可能需要使用代理对(surrogate pairs)来表示,即使用两个16位的值来组合成一个字符。

在Windows操作系统中,很多核心的系统组件和服务都基于UTF-16来处理字符串。例如,Windows API中的很多函数都接受UTF-16编码的字符串作为参数。此外,Windows的文件系统(NTFS)也支持UTF-16编码的文件名。

然而,这并不意味着Windows只使用UTF-16。在实际应用中,Windows也支持其他字符编码,特别是在与外部系统或网络进行交互时。例如,当Windows应用程序需要与网络上的其他系统交换文本数据时,它们可能会使用UTF-8编码,因为UTF-8是一种在互联网上广泛使用的编码,具有很好的兼容性。

此外,Windows的文本处理API也提供了在不同字符编码之间进行转换的功能,以便应用程序可以根据需要处理不同编码的文本数据。

因此,虽然Windows操作系统内部主要使用UTF-16编码来处理字符,但它也支持其他编码,并且提供了在不同编码之间进行转换的灵活性。

字符集是多个字符的集合,这些字符可以是各种文字、符号、标点符号、图形符号和数字等。而字符编码则是将这些字符集中的字符转换为计算机可以理解和处理的二进制形式,以便在计算机中进行存储、传输和处理。

具体来说,字符编码的作用主要体现在以下几个方面:

传输数据:字符编码可以将字符转换为二进制形式,这样字符就可以在计算机网络上进行传输。不同的字符编码方案确保了数据在传输过程中的正确性和完整性。
存储数据:字符编码还可以将字符以二进制形式存储在计算机的内存或磁盘中。不同的字符编码方案决定了存储时所占用的大小和存储容量。
文本处理:通过字符编码,计算机系统能够处理和操作文本数据。例如,计算机可以识别、编辑、搜索和排序文本等操作。

字符编码的历史也经历了不断的发展和演变。最早建立的字符与十进制数字对应关系的是ASCII码(American Standard Code for Information Interface,美国标准信息交换代码)。之后,随着全球化和多语言处理的需求增加,出现了更多的字符编码方案,如Unicode字符集,它可以根据需要,以UTF-8、UTF-16、UTF-32等多种方法编码。

因此,操作系统的字符编码是计算机系统中非常关键的一环,它确保了字符在不同系统和环境之间的一致性和准确性。

【以上都是搜索文心一言3.5 。】
字符串在文本文件里显示出来是人类可阅读的字符,在计算机内部是按某种编码方法编码后的二进制数据。如'中'字,
b'\xe4\xb8\xad' #utf-8
b'\xff\xfe-N' #utf-16
b'\xff\xfe\x00\x00-N\x00\x00' #utf-32
b'\xd6\xd0' #gbk
源代码是文本文件, 如果是gbk编码,则输入法输入到源代码文件里的字符在内部按gbk编码,解释器的解码是utf-8的,这里有一重点要知道:解释器和源代码文件之间是直接按计算机内部的编码二进制数据处理的。
在c/c++里,mingw编译器,源代码文件如果是gbk,要用-finput-charset=gbk的编译器命令才行,因为mingw是utf-8解码的。 在py里如果源代码文件是gbk的,也要在头上加一行特殊注释。
win的终端是gbk编解码方案的,在c/c++里mingw编译器要加-fexec-charset=gbk,才能正常输出字符。py的解释器在windows或linux等平台上应该有相应的类似命令,但是不需要解释器用户来设置。
C++里是 源代码字符集(基础的和扩展的)、执行字符集(基础的和扩展的)。
py3的解释器说是支持了unicode,

【以下来自文心】
Python 源代码的字符集和执行字符集是两个不同的概念,但它们都与字符编码有关。

Python 源代码字符集
Python 源代码文件(通常是 .py 文件)可以包含多种字符集,包括 ASCII、UTF-8、Latin-1 等。从 Python 3 开始,强烈推荐使用 UTF-8 编码来编写源代码,因为 UTF-8 可以表示任何 Unicode 字符,具有广泛的兼容性和灵活性。

你可以在源代码文件的开头通过特殊的注释来指定字符编码,例如:

# -*- coding: utf-8 -*-
这一行告诉 Python 解释器,源代码文件使用 UTF-8 编码。如果你的源代码文件只包含 ASCII 字符,那么通常不需要这样的声明,因为 ASCII 是 UTF-8 的一个子集。

Python 执行字符集
当 Python 解释器执行源代码时,它会将源代码中的字符串转换为内部的 Unicode 对象。这意味着 Python 解释器内部处理的所有字符串都是 Unicode 字符串,不依赖于源代码文件的字符编码。

Python 的字符串类型(str)是 Unicode 字符串,它可以包含任何 Unicode 字符。Python 解释器在读取源代码文件时,会根据源代码文件指定的字符编码(或默认编码)将字节转换为 Unicode 字符串。一旦字符串被加载到内存中,它们就以 Unicode 形式存在,直到程序结束执行。

因此,执行字符集实际上在 Python 中是 Unicode,而不是特定的字节编码。当 Python 需要将 Unicode 字符串输出到外部系统(如文件、网络等)时,它会根据需要将 Unicode 字符串转换为适当的字节编码。

总结来说,Python 源代码字符集是指源代码文件本身使用的字符编码,而执行字符集是指 Python 解释器内部处理字符串时使用的字符集,即 Unicode。在编写 Python 代码时,推荐使用 UTF-8 编码来确保兼容性和灵活性。
【以上来自文心】

先不管源代码文本文件的编码,假设一律都是utf-8,这样这一端就没有任何疑问了(因为即使不是utf-8,只需要头上加一个特殊注释就一样了,到解释器都能正确地处理了。 所以这一端没有疑难点)。
py3支持unicode指你源代码文件里的那些字符串!
在解释器里,字符串都是以utf-8编码的二进制数据,
至于为什么在win的终端(它可是gbk)解码出来正常显示,它肯定有一个类似-fexec-charset=gbk的内部命令。
还有,为什么c/c++里char类型(而不是wchar_t, char16_t, char32_t, char8_t)里写中文,在编译器能正常处理?:因为把中文放到char类型里,实际上是按8位的二进制(字节串)处理的,但是编译器的编码、解码都正常工作。 用sizeof测试就会发现问题了,一个中字符并不是一个字节。要考虑到计算机内部都是二进制数据,编译器、解释器都是与内部的二进制数据直接交流,而没有我们人类看到的文本编辑器解码出来的字符。

经过以上的查阅和思考,现在开始看 ”第37章 unicode和字节串“
1, python3的改进实际上相当于 把基本的执行字符集由ASCII修改到utf-8了。没有了扩展的执行字符集。
【文心begin】
源字符集和执行字符集是编程和计算机领域中与字符编码相关的两个重要概念。

源字符集(Source Character Set)是指编辑/编译器所要处理的字符集合,这些字符用于书写源代码,如C语言源程序。源字符集由基本字符集、表示换行的字符和扩展字符等部分组成。对于C语言学习者来说,编辑/编译环境与应用程序运行环境重合时,可能意识不到源字符集的存在。

执行字符集(Execution Character Set)则是指源代码经过编译、链接后的可执行文件所使用的编码字符集。当程序实际执行时,内存中的字符串编码就是执行字符集。简单来说,执行字符集是应用程序实际运行时所处理的字符集合。

需要注意的是,源字符集和执行字符集可能并不相同,这取决于编辑/编译环境和应用程序运行环境的设置和配置。在实际编程中,理解并正确处理这两个字符集对于确保程序的正确性和兼容性至关重要。

2,
基本源字符集和扩展源字符集是编程语言中用于书写源代码的两种字符集合,它们各自具有不同的特点和用途。

基本源字符集通常包含编程所需的最基本、最常用的字符,例如字母(大小写)、数字、常见的标点符号以及一些运算符等。这些字符是构成编程语言语法的基础,用于表示变量名、函数名、关键字、数值、控制结构等。

扩展源字符集则是对基本源字符集的补充和扩展,它包含一些特殊字符或符号,用于表示更复杂的编程概念或操作。这些特殊字符可能包括一些不常用的符号、图形字符、控制字符等,用于实现特定的功能或提高代码的可读性和可维护性。

扩展源字符集的存在是为了满足编程语言不断发展的需求,以及适应不同编程任务和场景的需要。通过引入扩展源字符集,编程语言可以更加灵活和强大,能够表达更复杂的逻辑和操作。

需要注意的是,不同的编程语言可能对基本源字符集和扩展源字符集的定义和范围有所不同。因此,在学习和使用特定的编程语言时,需要查阅相关的文档和规范,了解该语言对字符集的具体要求和约定。

此外,随着编程技术的发展和国际化需求的增加,一些编程语言还支持Unicode等更广泛的字符集,以容纳更多的字符和符号,支持多语言编程和国际化开发。这使得编程语言更加开放和包容,能够适应更广泛的编程需求和应用场景。
【文心end】
听名字,源字符集是识别源代码中文字的, 执行字符集才是程序运行需要的, 执行字符集可以分基本的和扩展的2个字符集(就像py2里面一样), 
源字符集似乎用不着分基本的和扩展的?

第37章作者的组织顺序可能有些乱。py里可能没有人提源字符集和执行字符集,更不会提基本和扩展的源和执行字符集。
【文心begin】
在Python中,并没有像某些其他编程语言那样明确区分源代码的基本字符集和扩展字符集。Python使用Unicode字符集作为其源代码的字符集,这意味着Python源代码可以包含任何有效的Unicode字符。

Unicode是一个国际标准,旨在为全球的文字系统提供统一的编码。它包含了世界上几乎所有语言的字符,包括拉丁字母、中文、日文、阿拉伯文等等。因此,Python源代码可以包含这些字符集中的任何字符。

虽然Python没有像某些语言那样明确区分基本字符集和扩展字符集,但Python的语法确实定义了一些特殊字符,这些字符在源代码中有特定的含义。例如,冒号(:)用于定义代码块,缩进用于表示代码的结构,括号((), [], {})用于分组和定义作用域,等等。这些特殊字符是Python语法的一部分,而不是扩展字符集。

总的来说,Python使用Unicode字符集作为其源代码的字符集,并没有明确区分基本字符集和扩展字符集。但是,Python语法确实定义了一些特殊字符,这些字符在源代码中有特定的含义。

2,
在Python中,并没有明确区分执行基本字符集和扩展字符集的概念。Python的执行过程中,处理的是内部的数据结构,主要是字节码(bytecode)和对象,而不是直接处理字符集。

Python源代码在解释或编译时,会先将源代码中的Unicode字符(即源代码字符集)转换成Python虚拟机(或解释器)可以理解的字节码。这个转换过程是根据Python的语法规则进行的,而不是基于字符集的基本和扩展之分。

当Python虚拟机执行这些字节码时,它并不直接操作字符,而是操作Python对象。这些对象可以是整数、浮点数、字符串、列表、字典等。字符串对象在Python内部是以Unicode形式表示的,可以包含任何有效的Unicode字符。

因此,从执行的角度看,Python并不区分基本字符集和扩展字符集。它使用Unicode来统一处理字符串和其他文本数据,使得Python能够支持多语言编程和国际化。

需要注意的是,当Python与外部系统(如文件、网络、数据库等)交互时,可能会涉及到字符编码的转换。在这些情况下,Python提供了相应的编码和解码函数,允许程序员将Unicode字符串转换为特定的字节编码,或将字节编码解码为Unicode字符串。但是,这些转换是在与外部系统交互的层面上进行的,并不涉及Python内部执行时的字符集区分。
【文心end】

晚上7点半,
比如图像,叫做二进制数据,不应该叫做字符串了,但是本书里作者把二进制数据也叫做字符串,可能是延续python2的字符串模型。
还有个就是ASCII不应该叫做Unicode,但本书把ASCII也叫做Unicode。

37章题目解读, unicode主要指py3中普通str类型的字符编码从py2的ASCII改为了utf-8 。
字节串 指以字节为单位的字节(8位)序列。py中尽可能用 ASCII字母表示字节串,前面加b前缀(表示字节或二进制),不能用ASCII字母表示的即用十六进制表示。
字节串就是指二进制数据的表示?

37.1 py3中的字符串修改
py2的str和unicode,在py3中对应:str和bytes,
另外,py3新增了bytearray可变类型。

①处理非ASCII的Unicode文本。py3比py2对 文本编码的支持更直接、易用和无缝。
②处理二进制数据。需要理解py3的新的bytes对象,还要理解py3中 文本与二进制数据和文件之间不同于py2的更为严格的区别。

【py简单,而且度过前面这繁琐的一点儿,后面就比较快乐。】

37.2 字符串基础知识
py 的字符串模型,也就是说py里怎样组织和划分的字符串问题,比如py3里的模型是 str(统一Unicode),bytes(字节串,以字节为单位的字节序列),bytearray。而py2里的字符串模型是 str(包括ASCII字符串和字节串),unicode字符串。
py2里把字符串和字节串混合,用一个str类型表示,是有些不对的。因为字符串是字符类型, 字节串是任何类型的二进制数据,它们2个不应该是同一种东西。

字符在计算机中实际是如何表示的:在计算机内部是用数值(码点)代表字符,有不同的字符集编码方案。编码为码点和解码为字符要用一致或兼容的字符编码方案。

在文件中存储:存的是编码后的码点(只有用文本编辑器打开时才解码为字符)。
在内存中存储:内存中字符串也是编码后的码点。【所以作者在字符串这部分有些地方说的是有漏洞的。】只不过有可能在文件中可以按指定的编码比如utf-8,gbk等存储,而在内存中(实际指python解释器解释后的运行时内存中)只以utf-8编码,因为py3的解释器就是utf-8编码(字符串按utf-8编码)。即使你的源代码编码是比如gbk,用encoding=gbk特殊注释后在解释器中还能编码成utf-8 。

37.2.1 字符编码方案
字符串是字符的序列。
按字符集的不同,计算机中存储字符的具体二进制值不同。 例如当在文件中存储文本时,用的字符集编码决定了内容的不同。
字符集编码方案 是将单独字符映射到整数编码的标准。
例如ASCII,定义了从0-127的字符编码。
例如,'a' -- 97(0x61),可以存储在内存和文件的1个字节中。
ord('a')
hex(97)
chr(97)
为了容纳特殊字符,一些字符集编码方案把ASCII范围之外的128-255分配给特殊字符,还是1个字节。 其中一个叫Latin-1,广泛用于西欧地区。
chr(196)

而有些语言有如此多的字符,1个字节的容量显然是存不下的。Unicode更加的灵活,字符可以根据需要占用多个字节。

编码:根据字符集编码方案(如utf-16)把一个字符翻译为原始字节。
解码:根据编码方案,把一个原始字节翻译为字符。

对于python程序来说,解码后的字符串在内存中还是utf-8的字节串(二进制数据),只是在文本编辑器中显示给人类看是字符。
但是当这些字符串在文件中存储、在网络上传输、内嵌到文档和数据库中时,就可能被编码为各种不同编码的字节串。

对固定1字节的、4字节长的字符集编码方案,翻译过程很简单。但对于utf-8,utf-16这些变长的字符编码方案,翻译过程(主要是解码方向)就有些复杂。因为这个原因, 这些编码方案的映射有些特殊设计。

ASCII是Latin-1的子集,也是utf-8的子集。
反过来,utf-8和latin-1在0-127的范围也和ASCII兼容。

字节串尽可能以人类能阅读的ASCII字母显示。 实际上内部都是二进制。

py带有大约100种不同的编码表文件。 这样可以方便识别和阅读种编码的文本文件。

一些编码有多个名称,如latin-1, iso_8859_1 , iso_8859都是Latin-1的编码名称。

37.3 Py是如何在内存中存储字符串的
【4月20号,周六,上午8点,】
上面讲的各种字符编码方案(如utf8,utf16,gbk等)实际上只有当文本在文件和其它媒体中被存储或外部转移时才用到。 在内存中,python总是以utf-8编码的整数存储文本字符串(本书的原文是“以编码中立的格式存储解码后的文本字符串”。

全部文本处理都以这一种(utf-8编码的整数)内部字节串(二进制数据)进行。 只有当文本转移到文本文件、字节串或带有特定字符编码要求的API(比如windows操作系统的API要求utf-16)时,文本才被翻译为特定的字符编码方案。 一旦处于内存中,字符串就是utf-8字符编码后的整数(书里原文是“就没有任何编码”,指字符是文本编辑器显示给人类看的,在解释器,它是跟整数打交道的,根本没有字符。从这个角度上说“没有任何编码”。)
【所以要理解字节串指的就是二进制数据,字符串是众多数据类型中的一种,在内部它也是字节串(所有一切在计算机都是字节串bytes)。】

py在内存中存储文本的实际方式随时间变化了,从3.3起就有了很大变化:
py3.2及之前版本: 字符串在内部存储为utf-16编码。除非py被配置为使用utf-32 。
py3.3及之后版本: 使用可变长度的方案,就是utf-8,每字符可以有1,2,4字节。

unicode明确地要求我们从字符的角度,而不是从字节的角度思考字符串。是说延续自ASCII的“每字符一字节的想法”。

文本工具:
今天字符串长度实际与Unicode码点一致(码点是识别字符的序数)。例如内置的ord()函数现在返回一个字符的Unicode码点数。 len()返回字符个数,而不是字节个数。
文本尺寸:
utf-8是变长的。不是1字节。

这小节的关键在:编码过程大部分与文件和传输有关,一旦载入为python字符串,内存中的文本就没有了任何“编码”的概念(指就是utf8的整数),它们仅仅是一般化存储的unicode字符序列。
在py脚本(py源代码)中,字符串是作为python字符串对象来访问的。

37.3 python的字符串类型
字符串数据类型, 取决于py版本:py2对二进制数据和ASCII这样的1字节文本使用一个(没有分开)字符串类型来表示,用另一个特定的类型来表示富Unicode文本。
①str:8位文本和二进制数据。
②unicode表示unicode字符串。
这2种的操作集大多是重叠的。 py2的str用于(包括ASCII和Latin-1)的8位表示的文本,以及表示绝对字节值的二进制数据。
【认识python字符串、字节串概念和模型。】

相比之下,py3有3种字符串和字节串对象类型——1种用于文本数据,另2种用于二进制数据:
【按组织,作者心里是明白的,但讲出来不准确,二进制数据和字节串是同一种东西他应该说出来。字符串是众多数据类型中的其中一种字节串。这2个事情应该说明白就不会对初学者造成困难。】
①str表示unicode字符串。
②bytes表示二进制数据(包括编码的文本)
③bytearray,一种可变的bytes类型。
【我现在是完全能读懂作者的话了。因为我有了前置知识,而且借助文心一言解答了心里其它相关疑问,如源代码字符集、执行字符集。】

37.3.1 为什么会有不同的字符串类型
【其实字节串不应该划到字符串下面,但本书就是这样划分了。】
py3中所有3种字符串类型都支持类似的操作集(也就是很多方法和函数是共用的)。
py3的这一修改的主要目标是:把py2的普通字符串类型和unicode字符串类型合并到一个单独的字符串类型中,以支持简单文本和unicode文本。开发者是想消除py2中字符串类型二分的局面,并让unicode的处理更加自然。
为了实现这一点,py3在重定义的str类型中存储文本——一个可变的字符(不一定是1字节)序列。其中包含可能ASCII或utf-8的文本。
“在内存中按utf8存储,在文件中可以按指定编码存储。”
上午10点,
py3的unicode字符串不能用来表示字节(二进制数据),如图形和声音文件,等等。
为了支持对真正二进制数据的处理,py3引入了bytes类型(也叫字符串类型),——表示8位字节整数的不可变序列,尤其注意:当可能的时候它尽可能打印为ASCII字符(不能时即128-255之间则打印为十六进制)。

尽管bytes是一种不同的对象类型,但它几乎支持str类型所支持的全部运算:包括字符串方法、序列操作、甚至re模块的模式匹配;但不支持字符串格式化。

更详细地讲,py3的bytes对象其实只是一个小整数序列。
对一个bytes对象索引将返回一个int,分片一个bytes将返回另一个bytes。并且list()用于bytes对象将返回整数列表,而不是字符列表。

一个重要点: bytes对象打印为字符串,而不是(十六进制)整数。前面加b前缀。

尽管如此,py3开发者还添加了一个bytearray类型,它是bytes类型的一个变体,可变并支持原位置修改。 
支持str和bytes所支持的常见字符串操作,也支持列表的很多原位置修改操作(append,extend,为索引赋值)。 这对真正的二进制数据和简单的(ASCII)的文本类型都是有用的!
也就是说如果你是ASCII或Latin-1文本,那么使用bytearray最终会为文本数据添加直接原处可修改的能力!!
bytearray

37.3.2 文本和二进制文件
文件IO在py3也有所改进,以反映str/bytes的区分,py3在传输时自动支持编码unicode文本。 
py3在文本文件和二进制文件之间做了区分:
①文本文件: 文件以文本模式打开时,读取其数据会自动将其内容解码,并将解码的内容返回为一个str; 
写入内容时需要一个str,并在传输到文件之前自动编码它。
读和写都按平台默认编码(utf-8)或所提供的编码名称(参数)来翻译。
文本模式打开文件还支持统一的行尾转换和额外的编码说明参数。
②二进制文件: 小写的b打开模式说明符,将以 二进制模式打开一个文件,此时读取数据不会以任何方式解码它,而是直接返回其未经修改的原始内容,并将其作为一个bytes对象!
写入二进制数据类似地需要一个bytes对象。
二进制模式文件也接受一个bytearray对象作为写入到文件中的内容。

由于str和bytes之间的差距陡然,因此必须确定数据本质上是文本还是(其它)二进制,并在py源码文件中相应地使用str或bytes对象表示其内容。
①如果是图像、声音、经网络传输的数据、必须解压的打包二进制数据、或一些设备数据流,用bytes和二进制模式文件处理这种文件更合适。
②如果要处理的内容本质是文本化的,用str和文本模式打开文件。

注意:open()函数的模式字符串参数,在py3至关重要! 因为其内容不仅指定了一个文件处理模式,而且暗含了一个python对象类型。
如果有b,则用bytes对象表示文件的内容,
如没有b,则用str对象表示其内容。

文本模式也处理BOM 。

python2中,对unicode的文本文件,用codecs.open()来打开。具体略过。

37.4 编写基本的字符串
37.4.1 py3的字符串字面量
str()内置函数,
bytes()内置函数,
b'xxx'(或B'xxx')是bytes对象的字面值。
bytearray()内置函数创建bytearray对象,有多种可能的参数。

单引号、双引号、三引号,都产生str。
b'abc'创建bytes。 但是b'中文'语法错误。
bytes对象实际上是短整数序列,尽管它尽可能将自己的内容打印为字符。

bytes对象和str一样不可修改。

37.4.2 py3.3中的py2 unicode字面量
py2的u'xxxx', U'xxxx' unicode 字面量形式在py3.0中被移除了。
然而,为了增强向前和向后的兼容性,从py3.3起u'xxx',U'xxx'又可用了。 3.3中它们被当作普通的str字符串。
但是自己以后写unicode字面量应该按py3写,因为加u或U是多余的。

37.4.3 py2的字符串字面量

37.4.4 字符串类型转换
python3中,str和bytes对象禁止在表达式中自动地混合,并且它们传递给函数时不会自动地相互转换。
①str.encode() , bytes(S, encoding) 把字符串转换为字节串。
②bytes.decode(), str(B, encoding) 把字节串转换为字符串。
有2点注意:
①,虽然有默认编码, bytes()函数的编码名称参数必须是必选的!
②,str()函数虽然有不需要编码名称参数的重载,但是那个获得的不是我们这里要的str对象,所以str()函数的编码名称参数也必须是必选。
S = 'eggs'
bytes(S, encodidng ='utf-8')
B = b'spam'
str(B, encoding = 'utf-8')

37.5 编写Unicode字符串
为了在字符串中编写任意的、甚至一些无法在键盘上输入的Unicode字符,python的字符串字面量支持 '\xNN'十六进制转义 , '\uNNNN', '\UNNNNNNNN'Unicode转义。

37.5.1 编写ASCII文本
S = 'XYZ'

37.5.2 编写非ASCII文本
【晚上8点20, 又遇到需要理清思路和心里的问题的时候, 】
【文心begin】
Python可以很好地处理非ASCII文本,包括Unicode字符。在Python中,你可以直接在你的代码中使用非ASCII字符,或者使用Unicode转义序列来表示这些字符。

下面是一个简单的例子,这个例子使用了中文字符:

# 直接在字符串中使用非ASCII字符  
print("你好,世界!")  
  
# 使用Unicode转义序列  
print("\u4f60\u597d\uff0c\u4e16\u754c\uff01")
这两个print语句都会输出同样的结果:"你好,世界!"。

对于文件操作,如果你的文件包含非ASCII字符,你可能需要在打开文件时指定编码。Python 3默认使用UTF-8编码,但如果你的文件使用的是其他编码,你需要显式地指定。例如:

python
# 打开一个包含非ASCII字符的文件  
with open('example.txt', 'r', encoding='utf-8') as f:  
    content = f.read()  
    print(content)
在这个例子中,我们打开了一个名为'example.txt'的文件,该文件使用UTF-8编码。然后,我们读取文件的内容并打印出来。

记住,处理非ASCII文本时,确保你的编辑器、你的代码以及你的运行环境都使用相同的编码是非常重要的。这可以避免很多常见的编码问题。
【文心end】
【这本教材在全面性上非常好,但是在表达上很差,如果不是因为python本身简单加上有文心一言的帮助,这本书在文本字符方面对编程初学很难读明白,主要责任全是作者的表达不好。所以这本书很需要解读!】
【编写非ASCII的文本, 一种就是用输入法,一种就是用unicode转义或者十六进制转义!就这2种方法?带着此问题阅读这一小节。】

①十六进制转义或Unicode转义在文本字符串中嵌入 Unicode码点序数值。【注意这个是码点,不是unicode字符的编码!】
②十六进制转义 在字节串中嵌入字符的编码。【有2个注意点:一是这条是字节串字面值了,而不属于上面我划分的字符串(本书里字节串也说是字符串,造成混乱)了。第二这里是unicode字符 的编码,而不是码点了。 码点是一个整数序数值(即字符集中是第多少个字符),而编码是具体的字符集编码方案下的字节序列,这个是阅读这部分的前置知识的重点。 在ASCII,码点序数值和编码是一样的,但是前面说过对于utf-8这种变长字符编码,为了解码的考虑,字符不是按序数连续的(具体查utf-8的字符编排道理,本书里前面用一两句话也说了,就在本章),所以码点序数值和编码不同是显然的。】
文本字符串用码点序数值代替没有输入法、也没法复制该字符的情况下的Unicode字符的输入;
字节串 用字符的编码。

0xc4是码点值,但不是utf-8的编码。Ä,b'\xc3\x84'这个才是它的utf-8的编码。
chr()函数要传入的是码点值。而bytes的decode()方法需要的对象是编码,b''引号里面的是编码,而不能是码点值。
ord()得到的是码点序数值,而不是编码。 encode()方法能得到编码。

S = '\xc4\xe8' # 用码点序数值表示的unicode字符串。
S = '\u00c4\u00e8' # 用Unicode转义表示的unicode字符串。

十六进制转义要求恰好2个数位(8位的码点值),所以非常有限的那256个字符(也即是latin-1的字符集的所有字符)。
而Unicode转义的u和U分别要求恰好4个和8个十六进制数位,它们分别可以表示65536个字符(16位)和40多亿个字符(32位)。


37.5.3 编码和解码非ASCII文本
【编码非ASCII用encode()方法,解码非ASCII文本用decode()方法】
S = '\u00c4\u00e8'
S.encode('latin-1')
S.encode('utf-8')
如果把编码后的字符串(已经变为字节串了。【本书不区分字符串、字节串带来很多表达麻烦】)写入到文件中,再打开文件读取时就要按写入时相同的字符编码才能正确解码为字符串!
传递给open()函数的编码模式参数会引发读入时自动进行解码!

【解决了疑问就像是全是运气一样!! 对字符来说码点和字节的不同,这个知识就引导你一路到了这里。】

37.5.4 其它编码方案
utf16和utf32的码点值对大部分字符(除了ASCII字符)来说是不一样的。'\uxxxx'就是指定utf16码点序数值,'\Uxxxxxxxx'就是指定utf32码点序数值。而且这些\u, \U表示法能够和ASCII字符自由混合。
S = 'A\u00c4B\U000000e8C'  # 得到'AÄBèC'
S.encode('latin-1') # 
S.encode('utf-8') # 得到字节串bytes对象
S = 'A' + chr(0xC4) + 'B' + chr(0xE8) + 'C'

关于IBM机器上使用的cp500 即EBCDIC的一种编码,它编码ASCII的方案不同。
S= 'AÄBèC'
S.encode('cp500') # 
S.encode('cp850')

S = 'spam'
S.encode('cp500') # b'\xa2\x97\x81\x94' 字节不同于ASCII

#以下2种长度不同,但对'spam'码点序数一样,字节也一样
S.encode('utf-16') #b'\xff\xfes\x00p\x00a\x00m\x00'
S.encode('utf-32') #b'\xff\xfe\x00\x00s\x00\x00\x00p\x00\x00\x00a\x00\x00\x00m\x00\x00\x00'

【文心begin】
CP500和EBCDIC是两个不同的概念,但它们之间有一定的关联。

EBCDIC(Extended Binary Coded Decimal Interchange Code)是IBM于1963年至1964年间推出的字符编码表。它是根据早期打孔机式的二进制编码的十进制数(BCD,Binary Coded Decimal)排列而成的。在EBCDIC编码表中,特定的字节值被分配给不同的字符和控制功能。例如,在编码表中,0x00 - 0x3F及0xFF为控制字符,0x40为空格,0x41为不换行空格(no-break space),0xCA为选择性连字号(soft hyphen)等。

而CP500是一种具体的EBCDIC字符编码页面(code page),用于定义如何将特定的字符映射到特定的字节值。这意味着,当你在使用CP500编码时,你实际上是在使用基于EBCDIC的一种特定字符集。

因此,CP500和EBCDIC之间的关系是:CP500是EBCDIC编码的一种具体实现或变种,它定义了如何将字符映射到字节值。这种编码方式在IBM的某些系统和其他一些旧的或特定的应用环境中可能仍然被使用。

请注意,随着技术的发展和新的字符编码标准的出现(如UTF-8),EBCDIC和CP500等旧的编码方式已经逐渐被淘汰。然而,在处理一些旧的数据或特定的应用时,了解这些编码方式仍然是有帮助的。
【文心end】

37.5.5 字节串字面量:编码的文本
py3的str字符串可以用十六进制和unicode转义表示字符,
但是bytes字节串只能用十六进制转义。
实际上,bytes字节串必须被解码为str字符串,才可以将其打印为非ASCII字符。
S = '\xc4\xe8'
S = '\u00c4\U000000e8'

B = b'\xc4\xe8'
B.decode('latin-1')

字节字面量对ASCII字符会直接显示字符,如果大于127就进行转义。(字节就是8位,最大255)
另一方面,str字符串允许包含字面量包含源字符集中的任何字符。源字符集默认为utf-8 。 【源代码文件的字符集编码和源字符集编码的关系:源代码文件的编码比如是gbk,如果源代码里写了俄罗斯文,则python解释器不能把俄罗斯文正确转为程序运行时内部的utf-8 。】
B = b'AÄBèC' # 是错误的。
B = 'AÄBèC'.encode('utf-8') #b'A\xc3\x84B\xc3\xa8C'
utf-8和latin-1对127以后的字符字节串是不同的。

37.5.6 转换编码
【4月21号,上午10点50,已收到24寸4k显示器。
光在python的字符编码方面就用去了这么长时间,但是应该。这样疑问都解除了。另外,在windows上终端是codepage936也就是gbk,这个字符集里比如是没有阿拉伯字符等的,所以它必定不能解码这些字符。python解释器是utf-8,原理是什么?可以猜测,比如它的源字符集、执行字符集。】
到现在应该前面遇到的大部分疑问都解决了。 但是看到本章最后。
【通义begin】
Python解释器本身支持多种字符编码,包括UTF-8。当您说“Python解释器是UTF-8”时,通常指的是Python解释器默认处理源代码文件以及内部字符串时使用的编码为UTF-8。这意味着您的Python程序可以包含使用UTF-8编码的非ASCII字符(如中文、日文、韩文等)而不会出现编码错误。

另一方面,Windows终端(也称命令提示符或CMD)在显示文本输出时可能会使用不同的编码,通常是与系统区域设置相关的编码。对于中文版Windows,其默认的终端编码通常是GBK或CP936,这是一种用于简体中文的编码标准,与UTF-8并不兼容。

**原理冲突在于编码不一致导致的解码错误:**

1. **Python解释器读取和执行源代码:**
当Python解释器加载并执行您的源代码时,它会根据源代码文件顶部的编码声明(如`# -*- coding: utf-8 -*-`)或者如果没有显式声明则按照Python 3的默认行为(即UTF-8)来正确解码文件内容。这样,Python程序内部处理的字符串都是以Unicode形式存在,能够正确表示各种国际字符。

2. **Python程序输出到终端:**
当您的Python程序产生文本输出并通过标准输出(`stdout`)打印到Windows终端时,这些Unicode字符串需要被转换为字节序列,然后通过操作系统提供的API发送到终端。转换过程中,Python会使用一个默认的或用户指定的编码(可以通过`sys.stdout.encoding`查看)将Unicode字符串编码为字节串。

3. **Windows终端接收并显示字节序列:**
接收到这些字节序列后,Windows终端会尝试使用其自身的默认编码(GBK)来解码这些字节,将其还原为可显示的字符。如果Python输出的字节序列是使用UTF-8编码的,而终端却尝试用GBK解码,由于编码规则的不同,原本的Unicode字符可能无法正确解析,从而导致显示乱码。

总结来说,原理上的冲突在于:

- **编码阶段:** Python解释器处理源代码和内部字符串时使用UTF-8。
- **输出阶段:** Python程序按某种(可能是UTF-8)编码向终端输出字节序列。
- **显示阶段:** Windows终端预期接收并使用GBK解码这些字节序列来显示文本。

为了解决这种不匹配,确保Python程序输出能在Windows GBK编码的终端上正确显示,通常需要采取以下措施之一:

- **在Python程序中显式指定输出编码:**
使用如`sys.stdout.buffer.write()`配合`str.encode('gbk')`将Unicode字符串编码为GBK字节串再输出,确保与终端编码匹配。

- **设置Python环境或终端以使用统一的UTF-8编码:**
如使用命令行参数`-X utf8`启动Python解释器,或者设置环境变量`PYTHONUTF8=1`,使得Python的I/O流强制使用UTF-8编码。同时,配置Windows终端(如通过`chcp 65001`命令切换代码页至UTF-8)使其能正确显示UTF-8编码的文本。

通过以上方式协调Python解释器与Windows终端之间的编码设定,可以避免因编码不一致导致的乱码问题。


Python 3输出到Windows终端不会乱码的情况通常是因为以下几个原因:

1. **Python 3的默认编码设置与Windows终端编码相匹配:**
Python 3内部处理字符串时使用Unicode,当它输出到终端时,会自动使用与当前环境相适应的编码。如果Python解释器检测到或被配置为与Windows终端相同的编码(例如,都为UTF-8),那么在输出时会自动将Unicode字符串正确编码为与终端匹配的字节序列,从而避免乱码。

2. **明确设置了Python输出的编码:**
即使Python解释器的默认设置与Windows终端编码不匹配,如果在编写程序时显式指定了输出编码,比如通过设置`sys.stdout.encoding`为与终端相同的编码,或者使用`print`函数时传入`encoding`参数,确保输出的文本被正确编码为与终端一致的格式,也能避免乱码。

3. **Windows终端已配置为支持Unicode(如UTF-8):**
现代版本的Windows操作系统及其终端应用程序(如PowerShell或CMD)通常支持UTF-8编码。如果终端已经配置为使用UTF-8作为其默认编码(例如,通过设置系统区域设置或在终端内执行`chcp 65001`命令切换到UTF-8代码页),即使Python解释器默认使用其他编码,只要Python程序输出的是UTF-8编码的文本,也能在终端上正确显示。

4. **程序中涉及的文本数据已正确解码:**
如果Python程序从外部源(如网络、文件)获取文本数据,并在输出前确保进行了正确的解码(如从响应头或HTML元标签中获取实际的编码并使用该编码解码),那么输出到终端的文本已经是Unicode形式,只要终端支持相应的Unicode显示,就不会出现乱码。

综上所述,Python 3输出到Windows终端不会乱码,主要是因为实现了编码的兼容性与一致性,确保了从Python内部的Unicode字符串到终端显示的整个过程中的编码转换是准确无误的。这可能得益于:

- Python解释器与终端默认编码的匹配。
- 明确设置的输出编码与终端编码一致。
- 终端本身支持并配置为使用Unicode编码(如UTF-8)。
- 程序中正确处理了文本数据的解码过程。

确保这些因素中的至少一项得到满足,就可以避免Python 3在Windows终端上输出乱码。


GBK编码包括以下字符集:

1. **全部GB2312字符**:
GBK编码是基于GB2312-80标准扩展的,因此它包含了GB2312中定义的所有汉字和符号。GB2312是中华人民共和国国家标准,主要收录了常用汉字以及一些拉丁字母、希腊字母、数字、标点符号和其他一些特殊符号,共计6763个汉字和682个非汉字字符。

2. **大量扩充汉字**:
GBK对GB2312进行了大幅度扩充,增加了大量的生僻汉字和一些专业领域使用的汉字,以及一些少数民族文字。这些扩充的汉字主要来源于国际标准ISO/IEC 10646-1和国家标准GB13000-1中定义的中日韩(CJK)汉字。具体来说,GBK收录了约6080个来自GB 13000.1的CJK汉字,以及另外8160个汉字(包括部首和构件)。这部分汉字通常包括历史文献、人名、地名、古籍中出现的生僻字,以及一些科学研究、文学艺术等领域所需的专门汉字。

3. **其他符号和图形**:
GBK除了汉字外,还包含了其他符号和图形。根据您提供的资料,GBK总共有23940个码位,其中汉字(包括部首和构件)共21003个,这意味着剩下的2937个码位用于表示非汉字字符。这些字符可能包括数学符号、标点符号、制表符、控制字符、音标符号、部分拉丁字符、日韩字符以及其他一些图形符号。

4. **BIG5编码中的汉字**:
GBK还包含了BIG5编码中的所有汉字。BIG5是主要用于繁体中文(港澳台地区)的字符编码,因此GBK的这一特性使得其能够较好地支持繁体中文文本,增强了两岸三地汉字信息交换的兼容性。

总结起来,GBK编码涵盖了:

- GB2312中的全部汉字和符号。
- ISO/IEC 10646-1和GB13000-1中的大量中日韩汉字。
- 少数民族文字。
- 生僻汉字和专业领域的汉字。
- 非汉字符号和图形。
- BIG5编码中的所有汉字。

总计收录汉字约21003个,加上其他符号和图形,共计23940个码位。这样的设计使得GBK能够满足日常和专业用途的广泛需求,尤其对于当时中国大陆的中文信息处理环境而言,提供了丰富的字符支持和良好的向下兼容性。

GBK编码中确实包含了部分俄文字符。虽然GBK主要设计用来支持简体中文和部分繁体中文字符,但它也扩展了对其他语言字符的支持,其中包括俄语字母。由于GBK兼容GB2312,并在此基础上进行了扩展,而GB2312就已经包括了少量的西文字符,如拉丁字母、希腊字母等。GBK进一步扩展了这种支持,加入了更多的非中文字符,其中包括俄语字母。

虽然GBK对俄文字符的支持不如专门为多语言环境设计的Unicode那样全面,但它涵盖了基本的俄语字母表,足以处理一些常见的俄语文本。然而,对于包含大量俄语词汇或专有名词,尤其是那些使用非基本字母组合(如带重音或特殊变体的字母)的复杂文本,GBK可能无法提供完整的覆盖。

综上所述,GBK编码确实包含了俄文字符,但其对俄语的支持程度相对有限,主要适用于包含少量俄语字符的混合文本环境。对于需要全面支持多种语言应用,尤其是专注于俄语文本处理的场景,建议使用Unicode编码(如UTF-8)以确保所有字符都能准确无误地表示和处理。

GBK字符集虽然在设计时考虑了一定的多语言支持,但其主要目标还是为了覆盖简体中文、繁体中文以及一些常见的符号和部分其他东亚语言字符。相对于全球众多的语言和字符集,GBK并不包含所有国家或地区的字符。以下是一些例子:

印度语系字符: GBK并未包含印度语系(如印地语、孟加拉语、泰卢固语、马拉雅拉姆语等)的天城文(Devanagari)、孟加拉文、泰卢固文、马拉雅拉姆文等复杂的字符集。这些语言使用完全不同于汉字的字母系统,且字符数量庞大,不在GBK的设计范围内。

阿拉伯语字符: 阿拉伯语使用阿拉伯字母体系,其字符形状随位置(起始、中间、结束、独立)变化,且包含特殊的连字规则。GBK并未包含这些特殊的阿拉伯字母及其变体,也无法支持阿拉伯语的连字显示。

希伯来语字符: 希伯来语使用从右向左书写的希伯来字母,其字符形态和排列方向与拉丁字母截然不同。GBK未包含希伯来字母,因此无法正确表示希伯来语文本。

泰语字符: 泰语使用泰语字母(又称泰文或泰语素可泰文),包含44个基础字母和多种声调符号、组合形式。这些字符也不在GBK字符集中。

斯拉夫语系字符: 虽然GBK包含了一些俄语字符,但对斯拉夫语系其他语言(如波兰语、捷克语、斯洛伐克语、塞尔维亚语、克罗地亚语等)所使用的某些特定字符(
【通义end】
'आ'.encode() #这是一个印度语字符
b'\xe0\xa4\x86'
'आ'.encode('gbk')
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
'आ'.encode('gbk')
UnicodeEncodeError: 'gbk' codec can't encode character '\u0906' in position 0: illegal multibyte sequence
encoding with 'gbk' codec failed

但是在idle的交互式解释器和终端的交互式解释器里都能print这个字符,而且sys.stdout.encoding得到utf-8,这说明,python的Windows终端是设置为utf-8编码了。 单独在终端运行chcp得到code page 936,是gbk的。由python解释器启动的windows终端是设置为utf-8编码的!!
用pyinstaller打包为exe后仍然能输出这个印度语字符。所以没有要担心的了!也没有疑问了,就是在windows下python解释器启动的终端窗口被设置为utf-8编码了!

【通义begin】
关于pyinstaller:
PyInstaller是一个用于将Python程序打包为独立可执行文件的工具,可以在Windows、Linux、macOS等平台上使用。以下是一份详细的PyInstaller用法指南:

### 1. 安装PyInstaller

确保您已安装Python和`pip`(Python包管理器)。在命令行环境中,使用以下命令安装PyInstaller:

```bash
pip install pyinstaller
```

### 2. 打包基本操作

#### **基本打包:**

将单个Python脚本(例如`your_script.py`)打包成一个目录结构,其中包含主可执行文件及必要的依赖文件:

```bash
pyinstaller your_script.py
```

这会在当前目录下生成一个名为`dist`的目录,里面包含打包后的可执行文件和依赖文件。执行文件位于`dist/your_script`(Windows)或`dist/your_script`(Linux/macOS)。

#### **单文件打包:**

如果您希望生成一个单一的、自包含的可执行文件(所有依赖都内嵌在一个文件中),使用`--onefile`选项:

```bash
pyinstaller --onefile your_script.py
```

这将在`dist`目录下生成一个名为`your_script`(Windows)或`your_script`(Linux/macOS)的单个可执行文件。

### 3. 更高级的打包选项

除了基本打包,PyInstaller还提供了许多选项来定制打包过程。以下是一些常用的选项:

#### **指定输出路径:**

使用`--distpath`或`-d`指定打包后文件的存放目录:

```bash
pyinstaller --distpath /path/to/output your_script.py
```

#### **指定工作目录:**

使用`--workpath`或`-w`指定临时工作目录(PyInstaller分析和构建过程的目录):

```bash
pyinstaller --workpath /path/to/workdir your_script.py
```

#### **添加图标:**

给生成的可执行文件指定一个图标(Windows和macOS):

```bash
pyinstaller --onefile --icon=my_icon.ico your_script.py
```

#### **清理缓存和临时文件:**

在打包前清理PyInstaller缓存和临时文件:

```bash
pyinstaller --clean your_script.py
```

#### **指定UPX压缩:**

使用UPX(如果已安装)对生成的可执行文件进行压缩,减小文件大小:

```bash
pyinstaller --onefile --upx-dir=path/to/upx your_script.py
```

#### **控制日志级别:**

调整PyInstaller的输出日志级别(如DEBUG、INFO、WARN等):

```bash
pyinstaller --log-level=DEBUG your_script.py
```

#### **隐藏console窗口(仅Windows):**

对于GUI应用,可以隐藏命令行窗口:

```bash
pyinstaller --windowed --onefile your_script.py
```

或使用等价的选项:

```bash
pyinstaller --noconsole --onefile your_script.py
```

### 4. 使用.spec文件

对于更复杂的打包需求,可以创建一个`.spec`文件来精细控制打包过程。`.spec`文件是一个包含了PyInstaller配置信息的文本文件。首先,使用`pyinstaller`命令自动生成一个`.spec`文件:

```bash
pyinstaller --name=YourAppName --onefile your_script.py
```

这将生成一个名为`your_script.spec`的文件。编辑此文件以调整配置,然后直接运行`.spec`文件进行打包:

```bash
pyinstaller your_script.spec
```

### 5. 其他注意事项

- 确保您的Python环境包含所有必要的依赖库,并且它们已被正确安装。PyInstaller会尝试捕获这些依赖,但如果遇到动态导入或其他复杂依赖情况,可能需要手动干预。
- 对于特定的库或框架(如Qt、Tkinter、wxPython等),可能需要额外的配置或插件才能正确打包。
- 测试打包后的可执行文件在目标机器上的运行情况,确保所有资源(如数据文件、配置文件等)被正确打包或能找到。

通过灵活运用上述选项和技巧,您可以根据项目的具体需求定制Python程序的打包过程,生成适用于不同平台的独立可执行文件。如果遇到问题,查阅PyInstaller官方文档或相关社区资源可以获得更详细的帮助和解决方案。
【通义end】

回到本节内容: 把一个字符串转换为不同于其原始编码的另一种编码:显式地提供一个编码名称。
以一种编码读取数据,而转为另一种编码存储数据,以便能够支持相同数据的多个客户端:
实践中,人们往往用输入法或网上查找到非ASCII Unicode字符串在代码中输入原始文本,而不是使用Unicode和十六进制转义来输入这些字符串。

对于文件,比如文本文件,里面是某种编码的字节串,被读入python程序时,传一个(比如你知道它的具体编码)编码名称参数,读进python程序来,会被解码为字符串,而不是还是字节串。python程序读一个utf-8编码的文本文件很简单。但当读一个gbk编码的文本时,读进来将gbk编码的字节串转为utf-8的码点的字符串! 这里确定有一个转换的! 如果要输出到终端,【涉及到文件IO操作。】
【通义begin】
在Python中,读取一个GBK编码的文本文件时,需要将读取到的GBK编码的字节串转换为UTF-8编码的字符串。这个过程包括两步操作:首先,将GBK编码的字节串解码为Unicode字符串(即得到Unicode码点的序列);然后,将得到的Unicode字符串重新编码为UTF-8编码的字节串。以下是具体的操作步骤:

**步骤1:读取GBK编码的文本文件**

使用`open()`函数以文本模式打开文件,并指定编码为`'gbk'`,读取文件内容:

```python
with open('gbk_encoded_file.txt', mode='r', encoding='gbk') as file:
    gbk_text = file.read()
```

在这个例子中,`gbk_text`变量存储了从GBK编码文件中读取的文本内容,此时它已经被解码为Unicode字符串。

**步骤2:将Unicode字符串编码为UTF-8**

使用`encode()`方法将Unicode字符串`gbk_text`编码为UTF-8编码的字节串:

```python
utf8_bytes = gbk_text.encode(encoding='utf-8')
```

现在,`utf8_bytes`变量就存储了UTF-8编码的字节串。

**总结:**

读取GBK编码的文本文件时,Python会自动将其内容解码为Unicode字符串(即码点的序列)。如果您需要将这个Unicode字符串转换为UTF-8编码的字节串,可以使用`encode()`方法完成这一操作。注意,这里的转换过程并非直接将GBK字节串转为UTF-8的码点字符串,而是先将GBK字节串解码为Unicode字符串,然后再将该Unicode字符串编码为UTF-8字节串。这是因为Python内部处理字符串时使用的是Unicode,而不是直接存储为某种特定编码的码点字符串。在实际应用中,通常是在需要将文本数据写入文件、网络传输或与其他系统交互时,才需要将Unicode字符串编码为特定的字节串(如UTF-8)。
【通义end】
【关键:py里字符串和字节串的区别:
str2 = '中' #
bytes2 = str2.encode() # b'\xe4\xb8\xad'
str2和bytes2 在内存中是一样的?错!
解码出来的文本在内存中是码点序数值,而字节串是字节。而字节和码点区别在前面有结论。
所以编码和解码的内存中的(也是实际的)含义是:字节和码点之间的转换!
【通义begin】
在Python中,解码字节串得到的文本(即字符串)在内存中确实是存储为Unicode码点的序列,而非直接存储为字节。而字节串则是以字节为单位的二进制数据序列。

**解码字节串得到的文本(字符串):**

当对一个字节串进行解码时,Python会依据指定的字符编码(如UTF-8、GBK等)将字节序列转换成相应的Unicode字符序列。每个Unicode字符由一个唯一的码点(Unicode code point)标识,码点是一个整数值,通常以十六进制表示。在Python内部,字符串实际上是Unicode码点的有序集合。这些码点按照Unicode标准映射到具体的字符,如字母、数字、标点符号、汉字等。

例如,对于字节串 `b'\xE6\x88\x91\xE7\x9A\x84'`(假设为UTF-8编码的汉字“我的”),解码后得到的字符串在内存中存储为两个Unicode码点:`U+6211`(我)和`U+7684`(的)。这些码点并不是以字节形式存储,而是以Python内部表示Unicode字符的方式存储,通常是一个能够容纳足够大整数的内部数据结构。程序员在编写代码时通常不需要直接接触这些内部表示,而是通过字符串的各种操作(如索引、切片、拼接等)来处理这些字符。

**字节串(bytes对象):**

字节串,即`bytes`对象,在Python中是一个不可变序列,其元素是单个字节(8位二进制数)。每个字节的值范围是0到255(十进制)。字节串通常用于表示二进制数据,如网络传输的数据、图像、音频、视频等原始比特流,或者是经过特定字符编码(如UTF-8、GBK等)转换后的文本数据。

例如,字节串 `b'\xFF\x00\xAA\xBB'` 包含四个字节,每个字节分别表示二进制值 `11111111`、`00000000`、`10101010` 和 `10111011`。这些字节直接存储在内存中,每个字节占用8位空间。

**总结:**

- 解码字节串得到的文本(字符串)在Python内存中是以Unicode码点的序列存储的,每个码点代表一个具体的字符,码点是整数值,不是字节形式。

- 字节串(`bytes`对象)则是字节的有序序列,每个字节是8位的二进制数,直接存储在内存中,用于表示二进制数据或编码后的文本数据。
【通义end】

with open(file_path, mode='r', encoding='gbk') as file:
    for line in file:
        print(line.rstrip('\n'))  # 去除每行末尾的换行符,确保在终端输出时格式整齐

【通义begin】
要使用Python读取GBK编码的文本文件,并将其内容输出到终端,您可以按照以下步骤操作:

```python
# 定义文件路径
file_path = 'example.txt'

# 使用open函数打开文件,指定'rb'模式(二进制读取)并传入'gbk'作为编码参数
with open(file_path, 'rb') as file:
    # 使用decode方法将读取到的二进制数据解码为字符串
    content = file.read().decode('gbk')

# 输出解码后的字符串到终端
print(content)
```

这里的关键点在于:

1. 使用`open()`函数打开文件时,指定模式为`'rb'`(二进制读取模式),因为文件的实际内容是以字节形式存储的,尤其对于非ASCII编码(如GBK)的文本文件。

2. 在`open()`函数中通过`encoding='gbk'`参数明确指定文件的编码为GBK,这样Python在读取文件时就会按照GBK编码规则解析字节流。

3. 使用`file.read()`方法读取文件的所有内容,得到的是字节串(bytes object)。

4. 调用字节串的`decode('gbk')`方法,将字节串解码为Unicode字符串。这里的参数`'gbk'`再次指定了解码所用的编码方式。

5. 最后,使用`print()`函数将解码后的Unicode字符串输出到终端。现代终端通常能正确显示Unicode字符,因此无需担心输出端的编码问题。

请确保替换`example.txt`为实际的GBK编码文本文件路径。运行上述代码后,您将在终端看到文件内容正确显示。
【通义end】
文件open()接口会自动完成大多数转换工作!

37.5.7 在python2中编写Unicode字符串
 


http://www.ppmy.cn/news/1428250.html

相关文章

面试经典150题——O(1) 时间插入、删除和获取随机元素

面试经典150题 day12 题目来源我的题解方法一 ArrayList不满足时间复杂度为O(1)方法二 ArrayListHashMap 题目来源 力扣每日一题&#xff1b;题序&#xff1a;380 我的题解 方法一 ArrayList不满足时间复杂度为O(1) 直接使用ArrayList存储 时间复杂度&#xff1a; insert&am…

每日三个JAVA经典面试题(四十四)

1.什么是反应式编程&#xff1f;它如何优化Web应用的性能&#xff1f; 反应式编程是一种编程范式&#xff0c;它通过异步数据流的方式处理事件和数据&#xff0c;以实现高效的数据处理和事件驱动的程序设计。在反应式编程中&#xff0c;数据流可以被观察&#xff08;Observabl…

Learn ComputeShader 01 First Computer Shader

使用Unity版本&#xff1a;2019.4.12f1 整体流程&#xff1a; 1添加一个quad object并添加一个无光照材质 2.相机投影模式设置为正交 3.调整quad使其完全显示在相机内 4.创建脚本并且使用计算着色器覆盖quad的纹理 5.创建一个compute shader 前三步完成以后结果应该是这…

怎么直连某个服务器的dubbo服务

有时候我们可能和别的部门或者业务之间共同开发某个需求&#xff0c;这个时候&#xff0c;我们可能环境不统一&#xff0c;我们调用在做dubbo调用的时候&#xff0c;可能会调用到其他的环境&#xff0c;导致无法引用对方最新的代码及逻辑&#xff0c;所以&#xff0c;在某些时候…

什么是RESTful?相关的注解有哪些?

哈喽&#xff0c;大家好呀&#xff01;这里是码农后端。RESTful在我们开发过程中可以说是再常见不过的了&#xff0c;但可能有一些新手小伙伴在刚开始学的时候会有一些疑惑&#xff0c;因为里面涉及到了较多的与操作相关的注解&#xff0c;因此&#xff0c;这里就来简单地总结一…

【JAVA基础篇】泛型详解版

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 目录 1.泛型的认识 2.泛型类 3.泛型方法 4.泛型接口 5.特别强调 6.类型通配符 简单化知识点&#xff0c;让你彻底了解泛型 1.泛型的认识 Java泛型是一种在Java编程语言…

【布客技术评论】大模型开源与闭源:原因、现状与前景

在人工智能领域&#xff0c;大模型的开源与闭源一直是一个备受争议的话题。近期&#xff0c;某大厂厂长说了“开源模型永远超不过闭源模型”&#xff0c;结果&#xff0c;脸书就发布了开源模型Llama3&#xff0c;超过了OpenAI 的闭源模型 GPT4。本文将探讨大模型开源与闭源的原…

使用mac自带服务器(一行命令即可启动)

打开终端&#xff0c;开启Apache: 开启apache: sudo apachectl start 重启apache: sudo apachectl restart 关闭apache: sudo apachectl stop 启动后地址&#xff1a; http://127.0.0.1/ mac下Apache服务器的文件路径&#xff1a; 点击Finder 然后按住快捷键CommandShiftG 输入…