操作数据:
字符串:Unicode 字符组成的序列,用于存储文本数据。
字节和字节数组:8比特整数组成的序列,用于存储二进制数据。
文本字符串
Unicode
1、Python3中的Unicode字符串
Unicode:为每个字符赋予了一个特殊的数字编码,这些编码与具体平台、程序、语言无关。 Unicode Code Charts页面 (http://www.unicode.org/charts/)包含了目前已定义字符集的链接。最新版 (6.2)定义超过了 110000种字符。 Python3中的字符串是Unicode字符串而不是字节数据,这是与Python2相比最大的差别。
Python中的unicodedata模块提供了下面两个方向的转换函数: lookup()——接受不区分大小写的标准名称,返回一个Unicode字符; name()——接受一个Unicode字符,返回大写形式的名称。
def unicode_test(value):
import unicodedata
name = unicodedata.name(value)
value2 = unicodedata.lookup(name)
print(‘value=”%s”, name=”%s”, value2=”%s”’ %(value,name,value2))
unicode_test(‘$’)
value=”$”, name=”DOLLAR SIGN”, value2=”$”
指定特殊的编码:
>>>import unicodedata
>>>unicodedata.name('\u00e9')
'LATIN SMALL LETTER E WITH ACUTE'
>>>unicodedata.lookup('LATIN SMALL LETTER E WITH ACUTE')
'é'
>>> place = 'caf\u00e9'
>>> place
'café'
>>> place = 'caf\N{LATIN SMALL LETTER E WITH ACUTE}'
>>> place
'café'
>>> u_umlaut='\N{LATIN SMALL LETTER U WITH DIAERESIS}'
>>> u_umlaut
'ü'
2、使用UTF-8 编码和解码
当需要与外界进行数据交互时需要完成两件事情:
a、将字符串编码为字节; b、将字节解码为字符串。
UTF-8动态编码方案:
a、为ASCII 分配1字节; b、为拉丁语系(除西里尔语)的语言分配2字节; c、为其他的位于基本多语言平面的字符分配3字节; d、为剩下的字符分配4字节,这包括一些亚洲语言及符号。 UTF-8是Python、Linux以及HTML的标准文本编码格式。
3、编码
编码是将字符串转化为一系列字节的过程。字符串encode()函数接受的第一个参数是编码方式名。可选的编码方式有:
ascii 经典的7比特ASCII编码
utf-8 最常用的以8比特为单位的变长编码
latin-1 也被称为ISO 8859-1编码
cp-1252 Windows常用编码
unicode-escape Python中Unicode的转义文本格式,\uxxxx 或者 \uxxxxxxxx
可以将任意Unicode数据以UTF-8的方式进行编码
>>> snowman=’\u2603’
>>> len(snowman) #snowman是一个仅包含一个字符的Unicode字符串
1
>>> ds = snowman.encode(‘utf-8’)
>>> len(ds) #单个Unicode字符snowman占用了3字节的空间
3
>>>ds # ds 是一个bytes类型的变量
b’\xe2\x98\x83’
encode()函数可接受额外的第二个参数帮助避免编码异常,默认值是’strict’
>>> snowman.encode('ascii','strict')
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
snowman.encode('ascii','strict')
UnicodeEncodeError: 'ascii' codec can't encode character '\u2603' in position 0: ordinal not in range(128)
>>> snowman.encode('ascii','ignore') #抛弃任何无法进行编码的字符
b’’
>>> snowman.encode(‘ascii’,’replace’) #将所有无法进行编码的字符替换为?
b’?’
>>> snowman.encode(‘ascii’,’backslashreplace’) #创建一个和unicode-escape类似的Unicode字符串
b’\\u2603’
4、解码: 解码是将字节序列转化为Unicode字符串的过程。
>>> place = 'caf\u00e9'
>>> place
'café'
>>> type(place)
<class 'str'>
>>> place_bytes = place.encode('utf-8')
>>> place_tytes
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
place_tytes
NameError: name 'place_tytes' is not defined
>>> place_bytes
b'caf\xc3\xa9'
>>> type(place_bytes)
<class 'bytes'>
>>> place2 = place_bytes.decode('utf-8')
>>> place2
'café'
## 格式化 ##
我们使用不同的格式化方法将变量插值(interpolate)到字符串中了,有两种格式化字符串的方式:旧时(old style)和新式(new style)。
1、旧式
数据转换类型:
%s 字符串
%d 十进制整数
%x 十六进制整数
%o 八进制整数
%f 十进制浮点数
%e 以科学计数法表示的浮点数
%g 十进制或科学计数法表示的浮点数
%% 文本值%本身
>>> ‘%s’ % 42
‘42’
>>> ‘%x’ % 42
‘2a’
>>> ‘%e’ % 7.03
‘7.030000e+00’
>>> ‘%d%%’ % 100
‘100%’
>>> n = 42
>>> f = 7.03
>>> s = ‘string cheese’
>>>’%d %f %s’ % (n,f,s)
’42 7.03 string cheese’
>>>’%10d %10f %10s’ % (n,f,s) #为每个变量设定最小域宽为10个字符,右对齐
‘ 42 7.030000 string cheese’
>>>’%10.4d %10.4f %10.4s’ % (n,f,s) #设定最小域宽10,最大字符宽度为4
‘ 0042 7.0300 stri’
>>>’%*.*d %*.*f %*.*s’ %(10,4,n,10,4,f,10,4,s) #将域宽/字符宽度设定作为参数
‘ 0042 7.0300 stri’
2、使用{}和format的新式格式化
>>> '{} {} {}'.format(n,f,s)
'42 7.03 string chess'
>>>’{2} {0} {1}’.format(f,s,n) # 新式格式化可指定插入的顺序 0,1,2:参数的位置
’42 7.03 string chess’
>>> d={‘n’:42,’f’:7.03,’s’:’string cheese’}
>>> ‘{0[n]} {0[f]} {0[s]} {1}’.format(d,’other’) # {0}代表整个字典,{1}代表字典后面的字符串
’42 7.03 string cheese other’
>>> ‘{0:d} {1:f} {2:s}’.format(n,f,s) #格式标识符放在 : 后面
’42 7.030000 string cheese’
>>>’{0:!^20s}’.format(‘BIG SALE’) #把空格以外的填充字符放在 : 之后,任何排版赋(<、>、^)和宽度标识符之前即可。
‘!!!!!!BIG SALE!!!!!!’
3、使用正则表达式匹配
正则表达式(regular expression):位于标准库模块re中,定义一个匹配的模式(pattern)字符串以及一个匹配的对象:源(source)字符串
>>> result = re.match(‘You’, ‘Young Frankenstein’) # ‘You’ 是模式,’Young Frankenstein’是源 match()函数用于查看源是否以模式开头。
>>> youpattern = re.compile(‘You’) #对模式进行编译以加快匹配速度
>>> result = youpattern.match(‘Young Frankenstein’) #直接使用已编译模式进行匹配
.match() 进行精准匹配
.search() 如果存在的话返回第一次成功匹配
.findall() 如果存在的话返回所有不重叠的匹配
.split() 根据pattern将source切分成若干段,返回由这些片段组成的列表
.sub() 需一个额外的参数replacement,把source中匹配的pattern替换为replacement
匹配功能的简单解释:
* 代表任意一个它之前的字符;
. 代表任意单一字符;
.* 代表任意多个字符(包括0个);
Frank是我们想要在源字符串中某处进行匹配的短语
二进制数据
需要了解字节序(endianness,处理器是如何将数据组织存储为字节的)以及整数的符号位(sign bit)之类的概念。
1、字节和字节数组:
. 字节是不可变的,像字节数据组成的元组; . 字节数组是可变的,像字节数据组成的列表。
>>> blist = [1,2,3,255]
>>> the_bytes = bytes(blist)
>>> the_bytes
b'\x01\x02\x03\xff' #bytes类型值的表示是以b开头,接着一个单引号,后面跟十六进制数
>>> the_byte_array = bytearray(blist)
>>> the_byte_array
bytearray(b'\x01\x02\x03\xff')
>>>
2、使用struct转换二进制数据
可使用struct模块的功能将二进制数据转换为Python中的数据结构 http://upload.wikimedia.org/wikipedia/en/9/95/O'Reilly_logo.png 大眼猴图片
struct.unpack():将数据类型转换为字节,正确解读字节序列并将它们组装成Python中的数据类型。
width,height = struct.unpack(‘>LL’, daa[16:24])
其中:’>LL’ 格式串,用于指导unpack()正确解读
> 用于指明整数是以大端(big-endian)方案存储的;
每个 L 代表一个4字节的无符号常(unsigned long)整数
struct.pack():将Python数据转换为字节
>>> import struct
>>> struct.pack(‘>L’, 154)
b’\x00\x00\x00\x9a’
>>> struct.pack(‘>L’, 141)
b’\x00\x00\x00\x8d’
字节序标识符
标识符 字节序
< 小端(到文件)方案
> 大端(在网络)方案
格式标识符
标识符 描述 字节
x 跳过一个字节 1
b 有符号字节 1
B 无符号字节 1
h 有符号短整数 2
H 无符号短整数 2
i 有符号整数 4
I(大写i) 无符号整数 4
l 有符号长整数 4
L 无符号长整数 4
Q 无符号long long型整数 8
f 单精度浮点数 4
d 双精度浮点数 8
p 数量和字符 1+数量
s 字符 数量
类型标识符紧跟在字节标识符的后面,任何标识符前面都可以添加数字用于指定需要匹配的数量。
其他二进制数据工具
第三方开源包提供了更加直观定义和提取二进制数据的方法: bitstring(https://code.google.com/p/python-bitstring/) construct(http://construct.readthedocs.org/en/latest/) hachoir(https://bitbucket.org/haypo/hachoir/wiki/Home) binio(http://spika.net/py/binio/)
安装construct包:
$ pip install construct
使用binascii()转换字节/字符串
标准binascii模块提供了在二进制数据和多种字符串表示(十六进制、六十四进制、uuencoded,等等)之间转换的函数。
位运算符: a(十进制 5, 二进制0b0101) b(十进制1,二进制0b0001)
运算符 描述 示例 十进制结果 二进制结果
& 与 a&b 1 0b0001
| 或 a | b 5 0b0101
^ 异或 a ^ b 4 0b0100
~ 翻转 ~a -6 取决于int类型的大小
<< 左位移 a << 1 10 0b1010
>> 右位移 a >> 1 2 0b0010