本文主要内容

字符

字节

结构体和内存视图

字符和字节之间的转换——编解码器

BOM鬼符

   标准化Unicode字符串

  Unicode文本排序

python高级——目录

文中代码均放在github上:https://github.com/ampeeg/cnblogs/tree/master/python高级

字符

'''
字符编码问题是经常困扰python编程人员的问题,我在编写爬虫的过程中也经常遇到这个头疼的事。 从python3开始,明确区分了人类语言(文本字符串)和机器语言(二进制字节),咱们先说文本字符串
开始之前,得对"字符"进行定义:
字符:Unicode字符,从python3的str对象中获取的元素是Unicode字符
字符串:字符串就是一个字符序列(这里对于(一)中内容相呼应) ''' if __name__ == "__main__":
# 创建字符
s1 = str('a')
s2 = 'b'
s3 = u'c'
print(s1, s2, s3) # a b c

  

  此时只用记住在python3中字符就是unicode,也就是str是unicode,这是人类能够看懂的语言。

字节

'''
python3中内置有两种基本的二进制序列类型:不可变的bytes和可变bytearray
(1)bytes和bytearray的各个元素是介于0~255(8个bit)之间的整数;
(2)二进制序列的切片始终是同一类型的二进制序列
''' if __name__ == "__main__":
# 创建bytes 和 bytearray
b1 = bytes('abc你好', encoding='utf8') # 关于encode稍后会说,不知道有没有人和我一样总是将编码与解码的方向混淆
print(b1) # b'abc\xe4\xbd\xa0\xe5\xa5\xbd' b2 = bytearray('abc你好', encoding='utf8')
print(b2) # bytearray(b'abc\xe4\xbd\xa0\xe5\xa5\xbd') # 切片(提示:序列都可以切片)
print(b1[3:5]) # b'\xe4\xbd'
print(b2[3:5]) # bytearray(b'\xe4\xbd') # 使用列表取值的方法试试
print(b1[3]) # 228 此时取出来的就不是字节序列了,而是一个元素
for _ in b1:
print(_, end=',') # 97,98,99,228,189,160,229,165,189, 这都是8bit的整数 # bytes的不可变 vs. bytearray的可变 # b1[3] = 160 # 报错:'bytes' object does not support item assignment
print(id(b2), b2) # 4373768376 bytearray(b'abc\xe4\xbd\xa0\xe5\xa5\xbd')
b2[2] = 78
print(id(b2), b2) # 4373768376 bytearray(b'abN\xe4\xbd\xa0\xe5\xa5\xbd') # 将b2转换成字符串看看
print(b2.decode('utf8')) # abN你好
# 注意,这里之所以能够用utf8转成unicode,是因为N的ascii码和utf8一致
b2.extend(bytearray('添加的内容', encoding='utf8')) # 既然是可变序列,bytearray当然拥有一般的序列的方法
print(id(b2), b2) # 4373768376 bytearray(b'abN\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xb7\xbb\xe5\x8a\xa0\xe7\x9a\x84\xe5\x86\x85\xe5\xae\xb9') print(b2.decode('utf8')) # abN你好添加的内容 # PS:大家可以将二进制序列当成列表,元素就是ascii编码(0~255)

结构体和内存视图

'''
struct可以从二进制序列中提取结构化信息。
struct模块提供了一些函数,可以将打包的字节序列转换成不同类型字段组成的元组;还有一些函数用于执行反向转换。
struct模块可以处理bytes、bytearray、memoryview对象。
''' import struct if __name__ == "__main__":
# memoryview类用于共享内存,可以访问其他二进制序列、打包的数组和缓冲中的数据切片,该操作无需赋值字节序列
fmt = '<3s3sHH' # 设置格式,< 是小字节序,3s3s是两个3字节序列,HH是两个16位二进制整数 with open('L3_图_python.jpg', 'rb') as f: # 需要在github中下载后运行
img = memoryview(f.read()) print(bytes(img[:10])) # b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x02\x00\x1c\x00\x1c\x00\x00'
print(struct.unpack(fmt, img[:10])) # (b'\xff\xd8\xff', b'\xe0\x00\x10', 17994, 17993) :拆包 del img

字符和字节之间的转换——编解码器

'''
python自带有超过100中编解码器,用于在字符串和字节之间相互转换。
每个编码都有多个名称,例如'utf_8'、'utf8'、'utf-8'、'U8',这些都可以传递给open()、str.encode()、bytes.decode()中的
encoding参数
''' if __name__ == "__main__":
# 看看不同的编码效果
for codec in ['gbk', 'utf8', 'utf16']:
print(codec, "你好".encode(codec), sep='\t')
'''
gbk b'\xc4\xe3\xba\xc3'
utf8 b'\xe4\xbd\xa0\xe5\xa5\xbd'
utf16 b'\xff\xfe`O}Y'
'''
# 咱们再来解码
print(b'\xc4\xe3\xba\xc3'.decode('gbk')) # 你好
print(b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('utf8')) # 你好
print(b'\xff\xfe`O}Y'.decode('utf16')) # 你好
'''
遇到编码问题一般很烦躁,下面来看看一般怎么解决编码问题。
(1)UnicodeEncodeError
(2) UnicodeDecodeError
''' if __name__ == "__main__":
# (1)UnicodeEncodeError
# 使用errors参数
s1 = "hello,你长胖啦".encode('latin-1', errors='ignore')
print(s1) # b'hello' 使用 errors='ignore' 忽略了无法编码的字符 s2 = "hello,你长胖啦".encode('latin-1', errors='replace')
print(s2) # b'hello?????' 使用errors='replace'将无法编码的字符用问好代替 s3 = "hello,你长胖啦".encode('latin-1', errors='xmlcharrefreplace')
print(s3) # b'hello,你长胖啦' 使用errors='xmlcharrefreplace'将无法编码的内容替换成XML实体 # (2) UnicodeDecodeError
# 乱码字符称为鬼符,以下实例演示出现鬼符的情况 s4 = b'Montr\xe9al'
print(s4.decode('cp1252')) # Montréal
print(s4.decode('iso8859_7')) # Montrιal
print(s4.decode('koi8_r')) # MontrИal
#print(s4.decode('utf8')) # 报错:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte
print(s4.decode('utf8', errors='replace')) # Montr�al
    '''
大多数人都遇到过乱码问题,并且可能总是调试不成功,这可能是各种程序之间的编码不匹配
以下代码引用自<流畅的python>,可以用来查看当前环境的一些默认编码
''' # -*- coding: utf-8 -*- import sys, locale expressions = """
locale.getpreferredencoding()
type(my_file)
my_file.encoding
sys.stdout.isatty()
sys.stdout.encoding
sys.stdin.isatty()
sys.stdin.encoding
sys.stderr.isatty()
sys.stderr.encoding
sys.getdefaultencoding()
sys.getfilesystemencoding()
""" my_file = open('dummy', 'w') for expression in expressions.split():
value = eval(expression)
print(expression.rjust(30), '->', repr(value)) '''
我电脑运行结果如下:
(' locale.getpreferredencoding()', '->', "'UTF-8'")
(' type(my_file)', '->', "<type 'file'>")
(' my_file.encoding', '->', 'None')
(' sys.stdout.isatty()', '->', 'True')
(' sys.stdout.encoding', '->', "'UTF-8'")
(' sys.stdin.isatty()', '->', 'True')
(' sys.stdin.encoding', '->', "'UTF-8'")
(' sys.stderr.isatty()', '->', 'True')
(' sys.stderr.encoding', '->', "'UTF-8'")
(' sys.getdefaultencoding()', '->', "'ascii'")
(' sys.getfilesystemencoding()', '->', "'utf-8'")
'''

BOM鬼符

 ''' 关于BOM的内容比较底层,以下内容全部选自<流畅的python> ''' 

标准化Unicode字符串

'''
初一看这个标题可能会有点蒙,难道Unicode本身还不够标准么?
先看看以下的例子:
'''
s1 = 'café'
s2 = 'cafe\u0301'
print(s1, s2) # café café
print(s1 == s2) # False '''
我们发现café可以用'café'和'cafe\u0301'两种方式表示,这个词对于人来说是一样的,但是这两种表示对于计算机来说确实不一样的
向这样的序列叫"标准等价物",在计算机中存储的值不相等,但应用程序应该认为相等。 要解决这个问题,需要用到unicodedata.nomalize函数,它的第一个参数可以选择这四种形式的一个:"NFC"、"NFD"和"NFKC"、"NFKD"
"NFC":使用最少的码为构成等价的字符串
"NFD":把组合的字符分割成基本字符和单独的组合字符 "NFKC"&"NFKD":这两种是较严格的规范形式,对"兼容字符有影响"
''' from unicodedata import normalize if __name__ == "__main__":
# "NFC" & "NFD"
print(s1.encode('utf8'), s2.encode('utf8')) # b'caf\xc3\xa9' b'cafe\xcc\x81'
s1 = normalize("NFC", s1)
s2 = normalize("NFC", s2)
print(s1, s2) # café café
print(s1 == s2) # True
print(s1.encode('utf8'), s2.encode('utf8')) # b'caf\xc3\xa9' b'caf\xc3\xa9' # "NFKC"&"NFKD"
# 这两种方式会损失信息,所以不建议使用,除非一些特殊情况,比如搜索和索引中
s3 = '½'
print(normalize('NFKC', s3)) # 1⁄2 将½转换成了1⁄2
s4 = '™'
print(normalize('NFKC', s4)) # TM 将™转换成了TM
    '''
另外,如果比较的时候不区分大小写,建议使用str.casefold(), 它与lower基本一致,其中大约有116个特殊的字符结果不同
'''
s5 = 'AKJkakshfKHDSdshfKSDShKkHkjhKJkgJhgJHkkHkjhJKhKJhK'
print(s5.casefold()) # akjkakshfkhdsdshfksdshkkhkjhkjkgjhgjhkkhkjhjkhkjhk

Unicode文本排序

'''
python比较序列时,会一一比较其中的元素。对于字符来说,比较的是其码位,主要是比较的ascii码;
非ascii文本的标准排序方式是使用locale.strxfrm函数,但是使用这个函数必须事先设定区域,但有些操作系统不支持,并且改变区域设置并不十分合适 建议使用pyuca.Collator.sort_key方法进行排序
''' if __name__ == "__main__":
# python默认的排序
fruits = ['caju', 'atemoia', 'cajá', 'açaí', 'acerola']
print(sorted(fruits)) # ['acerola', 'atemoia', 'açaí', 'caju', 'cajá'] # 但正确排序应该是:['açaí','acerola', 'atemoia', 'cajá', 'caju'] # 使用pyuca.Collator.sort_key import pyuca
print(sorted(fruits, key = pyuca.Collator().sort_key)) # ['açaí', 'acerola', 'atemoia', 'cajá', 'caju'] # pyuca可以将自定义排序表路径传递给Collator()构造方法,pyuca默认使用自带的allkeys.txt

python高级系列文章目录

python高级——目录

python高级(四)—— 文本和字节序列(编码问题)的更多相关文章

  1. 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】

    第二部分 数据结构 第2章 序列构成的数组 内置序列类型 序列类型 序列 特点 容器序列 list.tuple.collections.deque - 能存放不同类型的数据:- 存放的是任意类型的对象 ...

  2. Fluent_Python_Part2数据结构,04-text-byte,文本和字节序列

    文本和字节序列 人使用文本,计算机使用字节序列 1. 大纲: 字符.码位和字节表述 bytes.bytearray和memoryview等二进制序列的独特特性 全部Unicode和陈旧字符集的编解码器 ...

  3. 流畅的python第四章文本和字节序列学习记录

    字符问题 把码位转化成字节序列的过程是编码,把字节序列转化成码位的过程是解码 把unicode字符串当成人类可读的文本,码位当成机器可读的, 将字节序列编程人类可读是解码,把字符串编码成字节序列是编码 ...

  4. Python的文本和字节序列

    一.字符串的表示和存储 字符串是字符的序列,每个字符都有有一个数字作为标识,同时会有一个将标识转换为存储字节的编码方案: s = 'hello world python' for c in s: pr ...

  5. Python 文本和字节序列

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } Python 3 明确区分了人类可读的文本字符串和原始的字节序列.隐式 ...

  6. Python文本和字节序列

    ASCII码 早期人们用8位二进制来编码英文字母(最前面的一位是0) 也就是说,将英文字母和一些常用的字符和这128种二进制0.1串一一对应起来, 比如:大写字母“A”所对应的二进制位“0100000 ...

  7. python高级——目录

    目  录 python高级(一)—— python数据模型(特殊方法) python高级(二)—— python内置序列类型 python高级(三)—— 字典和集合(泛映射类型) python高级(四 ...

  8. Python数据类型之“文本序列(Text Sequence)”

    Python中的文本序列类型 Python中的文本数据由str对象或字符串进行处理. 1.字符串 字符串是Unicode码值的不可变序列.字符串字面量有多种形式: 单引号:'允许嵌入"双&q ...

  9. 【转】Python数据类型之“文本序列(Text Sequence)”

    [转]Python数据类型之“文本序列(Text Sequence)” Python中的文本序列类型 Python中的文本数据由str对象或字符串进行处理. 1.字符串 字符串是Unicode码值的不 ...

随机推荐

  1. 【小前端】float属性

    要求 需要float的元素,必须指定一个width宽度 没了 然后就可以指定 float:right 什么的了

  2. js常用utils

    var utils = { /** * 日期格式化 * * @param {Date} date 指定日期 * @param {String} format * @returns {String} * ...

  3. AspectJ AOP介绍

    idea下aspectj程序运行示例 有些同学可能想自己编写aspect程序进行测试练习,博主在这简单介绍运行环境的搭建,首先博主使用的idea的IDE,因此只对idea进行介绍.首先通过maven仓 ...

  4. 使用Qt Installer Framework制作软件安装包

    概述 Qt Installer Framework(缩写QIF)是Qt官方用于生成软件安装包的工具.包括Qt Creator和Qt Installer Framework自身的安装包都是由这个工具制作 ...

  5. 使用python把图片存入数据库-乾颐堂

    一般情况下我们是把图片存储在文件系统中,而只在数据库中存储文件路径的,但是有时候也会有特殊的需求:把图片二进制存入数据库. 今天我们采用的是python+mysql的方式 MYSQL 是支持把图片存入 ...

  6. Python监控日志程序-乾颐堂

    一个简易的日志监控的脚本,功能如下:1.windows环境2.当匹配日志关键字时会发出声音,匹配的关键字不同,播放的声音不同3.能做到实时响应 注意:是在win环境下哦 直接上代码吧 1 2 3 4 ...

  7. 使用PPT演讲时,两个屏幕显示的内容不一样

    使用PPT演讲时,两个屏幕显示的内容不一样 摘自:http://blog.sina.com.cn/s/blog_75f3150b01018f3l.html 参考1:https://jingyan.ba ...

  8. 轻松搭建持续集成工具jenkins

    1.Jenkins介绍1)什么是持续集成随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题.尤其是近些年来,敏捷(Agile) 在软 ...

  9. 如何让两个div并排显示

    正常情况下两个div都是上下排版的,那么怎么让它们并排显示呢? 方法一:都左浮动float:left; 方法二:一个左浮动,一个右浮动 方法三:给两个div都设置display:inline属性,但两 ...

  10. Sublime Text 3 -mac简体中文汉化包下载及教程

    Sublime Text 3下载 官方下载地址:http://www.sublimetext.com/3 汉化包链接 1.将上面要求下载的sublime_text_3.zip 文件解压,得到的Defa ...