6.0 Python 字节符与字节串

1. 字符编码

字符编码(Character encoding): 也称字集码, 为字符集中的字符指定唯一的二进制编码.
* 涉及字符串和文件必须要将字符编码理解透彻.

Unicode编码: 包含世界上所有的符号和二进制的对应关系.

基于Unicode编码设计的字符集:
UTF8: 可变长字符集, 使用1-4个字节表示一个字符, 多用于存储文件与传输文件...
UTF16: 使用2-4个字节表示一个字符, 因为UTF16可以使用2个字节代理成四个字节, 内存中统一使用的编码.
UTF32: 使用4个字节表示一个字符.

解决乱码的根本: 文件以什么编码方式存储到硬件中, 就必须以什么编码方式将文件读取出来.

2. Python编码

2.1 获取默认编码
# 获取默认的编码格式. 
import sys
# Python2为ascii, Python3为utf-8.
print(sys.getdefaultencoding())

2.2 Python3编码
源文件: 以UTF8编码方法存储, 编辑器则以UTF8解码方法打开并展示文本信息.

Python3默认的编码方式为UTF8, 意思就是: 运行时解释器以UTF8编码解释源文件.

* Python3的字符串单独使用'Unicode字符串'存储, 格式占2个字节,
引号语法创建的任何字符串都会存储为'Unicode'类型的字符串.
Unicode它本身收录所有的字符, 占用的字节和内存中占用的字节是一样的, 
在各国的计算机平台上解释的时候都不会乱码.
 Python 3 , 默认的字符编码是 UTF-8.
这意味着,  Python 3 中创建的字符串对象是以 Unicode 编码表示的.
# 这里的字符串是Unicode 编码.
s = '你好'

# 将unicode装换为gbk编码的二进制表示方式.
print(s.encode('gbk'))  # b'\xc4\xe3\xba\xc3'
# 将unicode装换为utf-8编码的二进制表示方式.
print(s.encode('utf-8'))  # b'\xe4\xbd\xa0\xe5\xa5\xbd'
2.3 Python2编码
源文件: 以UTF8编码方法存储, 编辑器则以UTF8解码方法打开并展示文本信息.

Python2比Unicode早诞生, 所以在内存中使用的不是Unicode编码, 而是ASCII编码.
运行时解释器以ASCII编码解释源文件.
Python语法使用的关键字, 变量名, 几乎都是英文(为什么说几乎, Python3可以使用中文作为变量名), 
而所有的字符集都兼容英文, 这部分代码不会出现编码问题.

在使用编辑器写代码的时候, 编辑器会将代码以utf8格式保存为文件, 在以utf8格式打开进行文件.
这个过程也不会出错.

在运行时, 如果注释和字符串中出现中文那么问题就来了, 
解释程序的编码与源文件使用的编码, 不一致, 就会出现乱码或报错, 基本原因如下:

* 1. 解释程序的编码表没有这个字符对应的二进制就会报错.

* 2. 不同的编码表字符和二进制的对应关系不一样.
     例如: 一种编码使用'0001'表示'你', 一种编码使用'0001'表示'我', 
     拿到'0001'二进使用不同的编码表翻译的意思就不一样.  
     
* 3. 不同的编码表可表示的范围不一样.
     例如: 某种编码只能解析1位二进制的的字符, 提供了一个2位的二进制的, 
     它可能会截取其中一部分区解析, 解析出来的意思就完全不一样.
# 在windows终端调用交互模式的时候, 会将默认编码改为GBK, 所有中文不会报错.
>>> x = '你打野!'
# Python2的字符串是使用Byte类型存储的, 打印字符串, 以Byte类型展示,
>>> x
'\xc4\xe3\xb4\xf2\xd2\xb0!'
# 在字符串前面添加u, 将字符串设置为Unicode字符串.
>>> x = u'你打野!'
>>> x
u'\u4f60\u6253\u91ce!'

1. 非ASCII字符异常
使用编辑器写代码是, 将源文件由UTF8字符集转换为ASCII编码, 解释源文件, 运到非ASCII字符报错.

解决非ASCII问题: 
编写源文件时可以通过声明编码的方式, 常用声明编码为 UTF8  GBK.
Python文件头部声明编码格式: 修改的是文件的默认编码格式, 
只是会影响Python解释器读取Python源文件时的编码格式, 并不会改变系统默认编码和本地默认编码.
声明编码后使用注释使用中文不会在出现问题, 可字符串中出现中文, 执行时还是会出现乱码的情况.

注意: 声明编码后, Pycharm的编辑器使用设置的编码作为保存文件的编码.
# 你打野!
print 123

2023-02-23_01725

2023-01-21_01695

运行程序时, 源文件由UTF8字符集转换为ASCII编码, 字符'你'的在UTF8编码的十六进制为'\xe4\xbd\xa0', 
ASCII编码无法解析\xe4, 就报异常了.
2. 以GBK格式解释源码
以GBK格式解释源码在Pycharm中运行出现乱码问题, 解决乱码的方法:
* 1. 修改Pycharm的项目编码改为GBK. 
     Pycharm的全局编码为UTF8, 项目编码也为UTF8( 显示<系统默认: GBK>, 是不生效的. ).
     File --> Setting --> Editor --> File Encodings.
     
* 2. Python2中增加了Unicode字符串, 将字符串设置为Unicodee字符串.
# coding=gbk
# 以gbk编码解释.
str1 = '你打野!'
print str1

2023-01-21_01696

image-20230121050857284

# coding=gbk
# 将字符串设置为unicode字符串. (如果设置了Pycharm的项目编码方式记得重置.)
str1 = u'你打野!'
print str1

image-20230128150045470

命令行模式运行程序, 则正常显示.

2023-01-21_01697

3. 以UTF8格式解释源码
以UTF8格式解释源码, 使用命名行模式运行会出现乱码和引发IoError异常, 解决方法:
* 1. 将字符串设置为Unicodee字符串.
* 2. 使用模块修改cmd的默认编码为UTF8.
# coding=utf8
str1 = '你打野!'
print str1

Pychamr中运行没有问题, 但是命令行方式运行出现乱码, 还引发了一个IOError的异常.
别人说的: 这个问题是windows实现C函数的问题: https://bugs.python.org/issue1602#msg148990

202301210545955

# coding=utf8
# 将字符串设置为unicode字符串. 
str1 = u'你打野!'
print str1

image-20230128151130492

# coding:utf-8
import os
# 安装模块: pip2 install win_unicode_console
# 此模式是用于在从 Windows 控制台运行 Python 时启用 Unicode 输入和显示.
import win_unicode_console

# 启用模块.
win_unicode_console.enable()

# 将cmd的显示字符编码从默认的GBK改为UTF-8.
# 默认情况下, 编码为936 (简体中文 GBK编码) 65001为UTF-8的代码页.
os.system("chcp 65001")  # 执行成功后打打印 Active code page: 65001
str1 = '你打野!'
print str1

image-20230121061405271

使用终端调用解释器交互环境时, 解释会使以GBK编码加载, 使用中文不会报错.

image-20221208171759137

3. bytes类型

3.1 字节串
bytes类型在Python中被称为'字节串', 不过很少有人说字节名字.
bytes类型: 使用引号引起来的一组字节序列, 将数据以字节的形式存储.
bytes类型以二进制字节序列的形式记录所需记录的对象(2进制太长, bytes类型最终以十六进制展示),
至于该对象到底怎么表示, 则由相应的编码格式解码所决定.
bytes通常用于网络数据传输, 二进制图片和文件的保存等.

在Python2中字符串就是字节串, Python3中新增bytes类型, 将字符串和bytes类型彻底分开了,
字符串使用Unicode类型存储, 不在使用字节串.
Bytes数据类型在所有的操作和使用甚至内置方法上和字符串数据类型基本一样, 也是不可变的序列对象.

* 字符串是以字符为单位进行处理的, bytes类型是以字节为单位处理的.
# Python2.
>>> s1 = '你好'
# windows终端使用GBK编码, 在交互模式打印字符串时, 展示文字对应的GBK编码的十六进制.
>>> s1
'\xc4\xe3\xba\xc3'

image-20221208163835353

\x是小写的十六进制转义字符, 每个十六进制数代表一个字节(八位二进制数).
字符'你'  '\xc4\xe3'表示.
字符'好'  '\xba\xc3'表示.
同一个字符串如果采用不同的编码方式生成bytes对象不一样.
# Python3
s1 = '你好'
print(s1)  # 你好
# Python3中的字符串是Unicode类型, 使用encode方法, 将Unicode类型转为成GBK格式Bytes类型.
s2 = s1.encode('gbk')
print(s2, type(s2))  # b'\xc4\xe3\xba\xc3' <class 'bytes'>

3.2 创建Bytes对象
# 字符串前面加上b表示Bytes类型字节串, 只允许在空字符串和纯英文字符串前面添加.
b1 = b''
print(b1, type(b1))  # b'' <class 'bytes'>

# 纯英文的字符, 可以直接在字符串前面加上b.
b2 = b'hello'
print(b2)  # b'hello'

# 使用bytes函数创建, bytes对象, 必须指定encoding参数设置编码方式.
b3 = bytes('你好', encoding='gbk')
print(b3)  # b'\xc4\xe3\xba\xc3'

b4 = '你好'.encode('gbk')  # 一个中文占用两个字节.
print(b4)  # b'\xc4\xe3\xba\xc3'

3.3 字节串与字符串转换
Python内置字节串与字符串互相转换的方法: (编码与解码仅针对字符串类型.)
bytes = str.encode('编码方式') 默认使用UTF8编码, 将str类型编程为bytes类型.
str = bytes.decode('解码方式') 默以使用UTF8解码, 将bytes类型解码成成str类型.

* 纯英文的字符, 可以直接在字符串前面加上b, 将str类型编程为bytes类型.

image-20221208050040442

# 纯英文的字符, 可以直接在字符串前面加上b
b1 = b'hello'
print(b1)  # b'hello'
# 解码, 默认按UTF8解码即可
print(b1.decode())  # hello

# Python3字符串使用的是Unicode编码, 也可以称为Unicode字符串.
str1 = '你好!'

# 字符串可以使用encode编码方法, 无法使用decode解码方法.
# 将Unicode编码转成UTF8.
e1 = str1.encode('UTF8')
print(e1, type(e1))  # b'\xe4\xbd\xa0\xe5\xa5\xbd!' <class 'bytes'>
e11 = str1.encode('UTF8')
# 不写编码类型, 默认以UTF8编码.
print(e11, type(e11))  # b'\xe4\xbd\xa0\xe5\xa5\xbd!' <class 'bytes'>

# 将Unicode编码转成GBK.
e2 = str1.encode('GBK')
print(e2, type(e2))  # b'\xc4\xe3\xba\xc3!' <class 'bytes'>


# 使用什么编码方式进行编码, 就需要什么编码方式进行解密, 否则乱码, 或报异常.
# 按UTF8解码bytes类型.
d1 = e1.decode('UTF8')
print(d1, type(d1))  # 你好! <class 'str'>
# 不写默认就是按UTF8解码.
d11 = e11.decode()
print(d11, type(d11))  # 你好! <class 'str'>

# 按GBK解码bytes类型.
d2 = e2.decode('GBK')
print(d2, type(d2))  # 你好! <class 'str'>
3.4 遍历字节串
s1 = '你好'
# 以utf8编码, 每个汉字占三个字节.
e1 = bytes(s1, encoding='utf8')
print(e1)
# bytes类型是以字节为单位处理的, 遍历字节串, 取出的是字节对应的十进制数.
for i in e1:
    print(i, hex(i), bin(i))

运行终端工具窗口显示:
b'\xe4\xbd\xa0\xe5\xa5\xbd'
228 0xe4 0b11100100
189 0xbd 0b10111101
160 0xa0 0b10100000
229 0xe5 0b11100101
165 0xa5 0b10100101
189 0xbd 0b10111101

相关推荐

  1. 关于python字节字符串的转换

    2024-06-16 01:42:02       8 阅读
  2. Python——字节bytes的编解码

    2024-06-16 01:42:02       33 阅读
  3. python字节和数字互转

    2024-06-16 01:42:02       13 阅读
  4. C语言每日一题(68)无重复字符的最长字

    2024-06-16 01:42:02       18 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-16 01:42:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-16 01:42:02       20 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-16 01:42:02       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-16 01:42:02       20 阅读

热门阅读

  1. React Native 快速Demo(1)

    2024-06-16 01:42:02       8 阅读
  2. 【React】在 react 应用中,怎么使用useReducer

    2024-06-16 01:42:02       11 阅读
  3. 前端面试题日常练-day67 【面试题】

    2024-06-16 01:42:02       8 阅读
  4. IEEE会议论文LaTeX模板中添加页码

    2024-06-16 01:42:02       7 阅读
  5. C++之结构体初始化使用总结

    2024-06-16 01:42:02       8 阅读
  6. 盘点热门开源大模型

    2024-06-16 01:42:02       7 阅读
  7. Android 应用程序 ANR 问题分析总结

    2024-06-16 01:42:02       6 阅读
  8. 时钟和系统控制

    2024-06-16 01:42:02       7 阅读
  9. 深度学习中的卷积算子优化与GPU加速

    2024-06-16 01:42:02       5 阅读