文本字符串
1. Unicode
1.1 Unicode字符串
Python3的字符串是Unicode字符串不是字节数组。这是与python2相比最大的差别。
- 用\u及4个十六进制的数字可以从Unicode256个基本多语言平面中指定一个特定某一特定字符。
- 我们需要使用更多的比特位来存储那些位于更高平面的字符。Python为此而设计的转义序列以\U开头,后面紧跟8个十六机制的数字,其中最左一位需为0。
- 也可以通过\N{name}来引用某一字符。
def unicode_test(value):
import unicodedata
name = unicodedata.name(value) #name()接受一个Unicode字符,返回大写形式的名称;
value2 = unicodedata.lookup(name) #lookup()接受不区分大小写的标准名称,返回一个Unicode字符;
print('value = "%s", name = "%s", value= "%s"' % (value, name, value2))
unicode_test('a')
#value = "a", name = "LATIN SMALL LETTER A", value= "a"
通过字符名称或者编码值来指定café这个词:
place = 'caf\u00e9'
print(place)
#café
place = 'caf\N{LATIN SMALL LETTER E WITH ACUTE}'
print(place)
#café
字符串函数len可以计算字符串中Unicode字符的个数,而不是字节数:
print(len('$'))
#1
print(len('\U0001f47b'))
#1
1.2 使用UTF-8编码和解码
当需要与外界进行数据交互时需要完成两件事情:
- 将字符串编码为字节
- 将字节解码为字符串
UTF-8是Python、Linux、以及HTML的标准文本编码格式。如果创建Python字符串时使用了从别的文本源(例如网页)赋值粘贴过来的字符串。一定要确保文本源使用的是UTF-8编码。
1.3 编码
编码是将字符串转化为一系列字节的过程。字符串的encode()函数锁接收的第一个参数是编码方式名。可选的编码方式列表如下:
编码 | 说明 |
---|---|
‘ascii’ | 经典的7比特ASCII编码 |
‘utf-8’ | 最常用的以8比特为单位的变长编码 |
‘latin-1’ | 也被称为ISO 8895-1编码 |
‘cp-1252’ | Windows常用编码 |
‘unicode-escape’ | Python中Unicode的转移文本格式,\uxxxx或\Uxxxxxxxx |
snowmain = '\u2603' #仅包含一个字符的Unicode字符串
print(len(snowmain))
print(len(snowmain.encode('utf-8'))) #将Unicode字符编码为字节序列,utf-8是一种变长编码方式。所以占用3字节的空间。编码后的snowmain变成了bytes类型(字节型)。 bytes类型是指一堆字节的集合,在python中以b开头的字符串都是bytes类型。
#1
#3
encode()函数可以接受额外的第二个参数来帮助我们避免编码异常。它的默认值是’strict’。
snowmain = '\u2603'
print(snowmain.encode('ascii', 'ignore'))
print(snowmain.encode('ascii', 'replace'))
print(snowmain.encode('ascii'))
#b''
#b'?'
'''
Traceback (most recent call last):
File "test.py", line 239, in <module>
print(snowmain.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 0: ordinal not in range(128)
'''
1.4 解码
解码试讲字节序列转化为Unicode字符串的过程。我们从外界(文件,数据库,网站,网络API等)获得的所有文本都是经过编码的字节串。我们需要知道它是以何种方式编码的,这样才能逆转编码过程以获得Unicode字符串。
place = 'caf\u00e9'
print(place)
place_encode = place.encode('utf-8')
print(place_encode)
print(place_encode.decode('utf-8'))
#café
#b'caf\xc3\xa9'
#café
尽可能统一使用UTF-8编码。出错率低,兼容性好,可以表达所有的Unicode字符,编码解码速度快等优点。
2. 格式化
Python有两种格式化字符串的方式。
2.1 使用%的旧式格式化
旧式格式化形式为string % data。它仅由%以及一个用于指定数据类型的字幕组成。
%s | 字符串 |
---|---|
%d | 十进制整数 |
%x | 十六进制整数 |
%o | 八进制整数 |
%f | 十进制浮点数 |
%e | 以科学计数法表示的浮点数 |
%g | 十进制或科学计数法表示的浮点数 |
%% | 文本值%本身 |
字符串和整数的插值操作:
action = 'hello'
num = 20
flow = 70.003
print('%s world' % action)
print('%d' % num)
print('%10d' % num)
print('%f' % flow)
print('%10f' % flow)
#hello world
#20
# 20
#70.003000
# 70.003000
2.2 使用{}和format的新式格式化
新式格式化最简单的用法如下:
a = 12
b = 7.03
c = 'hello'
print(f'{a} {b} {c}') #格式化字面量
print('{} {} {}'.format(a, b, c)) #format()方法
print('{b} {a} {c}'.format(a=11, b=7.01, c='world'))
#字典
d = {'a':1, 'b': 7.03, 'c':'world'}
print('{0[a]} {0[b]} {0[c]} {1}'.format(d, 'other'))
print('{0:d} {1:f} {2:s}'.format(a, b, c))
print('{a:d} {b:f} {c:s}'.format(a=41, b=7.01, c='else'))
#12 7.03 hello
#12 7.03 hello
#7.01 11 world
#1 7.03 world other
#12 7.030000 hello
#41 7.010000 else
3. 使用正则表达式匹配
3.1 模式匹配方法
import re
result = re.match('you', 'you are my') #第一个参数:匹配的模式(pattern);第二个参数:匹配的对象(source字符串)
print(result)
you = re.compile('you')
result = you.match('you are my') #从源字符串的开头开始匹配
print(result)
if result:
print(result.group())
are = re.search('are', 'you are my')
if are:
print(are.group())
are = re.search('.are', 'you are my') #返回第一次匹配成功
if are:
print(are.group())
are = re.search('.*are', 'you are my')
if are:
print(are.group())
are = re.match('.*are', 'you are my')
if are:
print(are.group())
#<re.Match object; span=(0, 3), match='you'>
#<re.Match object; span=(0, 3), match='you'>
#you
#are
# are
#you are
#you are
除了以上方法,还有findall()、split()、sub()等方法。
- 使用 . 代表任意除\n外的字符
- 使用 * 表示任意多个字符。(包括0个)
- 使用 ? 表示可选字符(0个或1个)
3.2 模式:特殊字符
模式 | 匹配 |
---|---|
\d | 一个数字字符 |
\D | 一个非数字字符 |
\w | 一个字母或数字字符 |
\W | 一个非字母或非数字字符 |
\s | 空白符 |
\S | 非空白符 |
\b | 单词边界 |
\B | 非单词边界 |
import string
import re
print(string.printable)
print(len(string.printable))
print(re.findall('\d', string.printable))
'''
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
100
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
'''
3.3 模式:使用标识符
表中:expr和其他斜体单词表示合法的正则表达式。
模式 | 匹配 |
---|---|
abc | 文本值abc |
(expr) | expr |
expr1|expr2 | expr1或expr2 |
. | 除\n外的任何字符 |
^ | 源字符串的开头 |
$ | 源字符串的结尾 |
prev? | 0个或1个prev |
prev* | 0个或多个prev,尽可能的多匹配 |
prev*? | 0个或多个prev,尽可能的少匹配 |
prev+ | 1个或多个prev,尽可能的多匹配 |
prev+? | 1个或多个prev,尽可能的少匹配 |
prev{m} | m个连续的prev |
prev{m, n} | m个到n个连续的prev,尽可能的多匹配 |
prev{m, n}? | m个到n个连续的prev,尽可能的少匹配 |
[abc] | a或b或c(和a|b|c一样) |
[^abc] | 非(a或b或c) |
prev(?=next) | 如果后面为next,返回prev |
prev(?!next) | 如果后面非next,返回prev |
(?<=prev)next | 如果前面为next,返回prev |
(?<!prev)next | 如果前面非next,返回prev |
import string
import re
source = 'you are you are you are hello world'
print(re.findall('are', source))
print(re.findall('^are', source))
print(re.findall('^you are', source))
print(re.findall('hello$', source))
print(re.findall('hello world$', source))
print(re.findall('you|are', source))
#['are', 'are', 'are']
#[]
#['you are']
#[]
#['hello world']
#['you', 'are', 'you', 'are', 'you', 'are']
3.4 模式:定义匹配的输出
当使用match()或searc()时,所有的匹配会以m.group()的形式返回到对像m中。如果用括号将某一模式包裹起来,括号中模式匹配得到的结果归入自己的group中,而调用group()可以得到包含这些匹配的元组。
import string
import re
m = re.search(r'(. are\b).*(\bhello)', source)
print(m.group())
print(m.groups())
#u are you are you are hello
#('u are', 'hello')
二进制数据
1.1 字节和字节数组
- 字节是不可变的,像字节数据组成的元组
- 字节数组是可变的,想字节数据组成的列表
blist = [1, 2, 3, 255]
the_bytes = bytes(blist)
print(the_bytes)
the_array = bytearray(blist)
print(the_array)
#b'\x01\x02\x03\xff'
#bytearray(b'\x01\x02\x03\xff')
print(the_bytes[0])
#1
the_bytes[0] = 1 #不可改变
#TypeError: 'bytes' object does not support item assignment
1.2 大小端
标识符 | 字节序 |
---|---|
< | 小端方案 |
> | 大端方案 |
1.3 位运算符
运算符 | 描述 |
---|---|
& | 与 |
| | 或 |
^ | 异或 |
~ | 翻转 |
<< | 左位移 |
>> | 右位移 |