re模块(正则模块)
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
\w 匹配字母数字及下划线
\W 匹配非字母数字下划线
\s 匹配任意空白字符,等价于【\t\n\r\f】
\S 匹配任意非空字符
\d 匹配任意数字,等价于【0-9】
\D 匹配任意非数字
\A 匹配字符串
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串
\z 匹配字符串结束
\G 匹配最后匹配完成的位置
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串的开头
$ 匹配字符串的末尾
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
[…] 用来表示一组字符,单独列出:【amk】匹配’a’,’m’或‘k’
[^…] 不在[]中的字符
* 匹配0个或多个的表达式
+ 匹配1个或多个的表达式
? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
{n} 精确匹配n个前面表达式
{n,m} 匹配n到m次由前面的正则表达式定义的片段,贪婪方式
a|b 匹配a或b
() 匹配括号内的表达式,也表示一个组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import
re
print
(re.findall(
'\w'
,
'hello_ | egon 123'
))
print
(re.findall(
'\W'
,
'hello_ | egon 123'
))
print
(re.findall(
'\s'
,
'hello_ | egon 123 \n \t'
))
print
(re.findall(
'\S'
,
'hello_ | egon 123 \n \t'
))
print
(re.findall(
'\d'
,
'hello_ | egon 123 \n \t'
))
print
(re.findall(
'\D'
,
'hello_ | egon 123 \n \t'
))
print
(re.findall(
'h'
,
'hello_ | hello h egon 123 \n \t'
))
print
(re.findall(
'\Ahe'
,
'hello_ | hello h egon 123 \n \t'
))
print
(re.findall(
'^he'
,
'hello_ | hello h egon 123 \n \t'
))
print
(re.findall(
'123\Z'
,
'hello_ | hello h egon 123 \n \t123'
))
print
(re.findall(
'123$'
,
'hello_ | hello h egon 123 \n \t123'
))
print
(re.findall(
'\n'
,
'hello_ | hello h egon 123 \n \t123'
))
print
(re.findall(
'\t'
,
'hello_ | hello h egon 123 \n \t123'
))
输出:
[
'h'
,
'e'
,
'l'
,
'l'
,
'o'
,
'_'
,
'e'
,
'g'
,
'o'
,
'n'
,
'1'
,
'2'
,
'3'
]
[
' '
,
'|'
,
' '
,
' '
]
[
' '
,
' '
,
' '
,
' '
,
'\n'
,
' '
,
'\t'
]
[
'h'
,
'e'
,
'l'
,
'l'
,
'o'
,
'_'
,
'|'
,
'e'
,
'g'
,
'o'
,
'n'
,
'1'
,
'2'
,
'3'
]
[
'1'
,
'2'
,
'3'
]
[
'h'
,
'e'
,
'l'
,
'l'
,
'o'
,
'_'
,
' '
,
'|'
,
' '
,
'e'
,
'g'
,
'o'
,
'n'
,
' '
,
' '
,
'\n'
,
' '
,
'\t'
]
[
'h'
,
'h'
,
'h'
]
[
'he'
]
[
'he'
]
[
'123'
]
[
'123'
]
[
'\n'
]
[
'\t'
]
|
re模块提供的方法:
re.findall() 查找所有满足匹配条件的结果,放在列表中
re.search() 只找到第一个匹配到的然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None
re.match() 同search,不过在字符串开始出进行匹配,完全可以使用search+^代替match
re.split() 按匹配内容对对象进行分割
re.sub() 替换,(老的值,新的值,替换对象,替换次数),不指定替换次数,默认替换所有
re.subn() 同sub,不过结果中返回替换的次数
re.compile 重用匹配格式
3、time模块
Python中,通常有以下三种方式来计算时间:
a.时间戳:
时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型
b.格式化的时间字符串
c.结构化的时间
struct_time元组共有9个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
4、random模块
5、os模块
6、sys模块
7、json和pickle模块(序列化模块)
把对象(变量)从内存中变成可存储或传输的过程称为序列化
在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等
序列化的作用:
a.持久保存状态
在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化
b.跨平台数据交互
序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling
json模块
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便,所以json适合数据跨平台交互时使用(但是跨平台意味着不会支持某种语言的所有数据类型,如不支持python函数的序列化)
内存中结构化的数据<---> 格式json <--->字符串 <---> 保存到文件中或基于网络传输
使用:
dump 序列化
load 反序列化
1
2
3
4
5
6
7
|
import
json
dic
=
{
'name'
:
'egon'
,
'age'
:
18
}
with
open
(
'a.json'
,
'w'
) as f:
# 序列化字典到文件内容
f.write(json.dumps(dic))
with
open
(
'a.json'
,
'r'
) as f:
# 反序列化输出
data
=
f.read()
dic
=
json.loads(data)
|
dumps 序列化
loads 反序列化
1
2
3
4
|
import
json
dic
=
{
'name'
:
'egon'
,
'age'
:
18
}
json.dump(dic,
open
(
'b.json'
,
'w'
))
# 序列化字典到文件内容
print
(json.load(
open
(
'b.json'
,
'r'
))[
'name'
])
# 反序列化输出
|
pickle模块
pickle只能用于Python(所有数据类型),并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
内存中结构化的数据<---> 格式pickl<---> bytes类型 <---> 保存到文件中或基于网络传输
dumps 序列化
loads 反序列化
dump 序列化
load 反序列化
1
2
3
4
5
6
7
|
import
pickle
dic
=
{
'name'
:
'egon'
,
'age'
:
18
}
with
open
(
'd.pkl'
,
'wb'
) as f:
# 序列化字典到文件内容
f.write(pickle.dumps(dic))
with
open
(
'd.pkl'
,
'rb'
) as f:
# 反序列化输出
dic
=
pickle.loads(f.read())
print
(dic[
'name'
])
|
1
2
3
4
|
import
pickle
dic
=
{
'name'
:
'egon'
,
'age'
:
18
}
pickle.dump(dic,
open
(
'e.pkl'
,
'wb'
))
# 序列化字典到文件内容
print
(pickle.load(
open
(
'e.pkl'
,
'rb'
))[
'name'
])
# 反序列化输出
|
pickle是根据内存地址进行反序列化的,所以该内存地址对应的数据在命名空间中必须是已定义的
8、shelve模块
9、shutil模块
高级的文件、文件夹、压缩包处理模块
常用方法:
将文件内容拷贝到另一个文件中:
shutil.copyfileobj(源文件, 目标文件[, length])
拷贝文件:
shutil.copyfile(src, dst) # 目标文件无需存在
仅拷贝权限。内容、组、用户均不变
shutil.copymode(src, dst) # 目标文件必须存在
仅拷贝状态的信息,包括:mode bits,atime, mtime, flags
shutil.copystat(src, dst) #目标文件必须存在
拷贝文件和权限
shutil.copy(src, dst)
拷贝文件和状态信息
shutil.copy2(src, dst)
递归的去拷贝文件夹
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None) #目标目录不能存在,注意对dst目录父级目录要有可写权限,ignore的意思是排除
拷贝软连接
import shutil
shutil.copytree('f1', 'f2', symlinks=True,ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
递归的去删除文件
shutil.rmtree(path[, ignore_errors[,onerror]])
递归的去移动文件,它类似mv命令,其实就是重命名
shutil.move(src, dst)
创建压缩包并返回文件路径,例如:zip、tar
shutil.make_archive(base_name, format,...)
base_name:压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径
如 data_bak =>保存至当前路径
如 /tmp/data_bak =>保存至/tmp/
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir:要压缩的文件夹路径(默认当前目录)
owner: 用户,默认当前用户
group: 组,默认当前组
logger: 用于记录日志,通常是logging.Logger对象
练习:
1
2
3
4
5
6
7
|
#将 /data 下的文件打包放置当前程序目录
import
shutil
ret
=
shutil.make_archive(
"data_bak"
,
'gztar'
, root_dir
=
'/data'
)
#将 /data下的文件打包放置 /tmp/目录
import
shutil
ret
=
shutil.make_archive(
"/tmp/data_bak"
,
'gztar'
, root_dir
=
'/data'
)
|
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import
zipfile
# 压缩
z
=
zipfile.ZipFile(
'laxi.zip'
,
'w'
)
z.write(
'a.log'
)
z.write(
'data.data'
)
z.close()
# 解压
z
=
zipfile.ZipFile(
'laxi.zip'
,
'r'
)
z.extractall(path
=
'.'
)
z.close()
import
tarfile
# 压缩
t
=
tarfile.
open
(
'/tmp/egon.tar'
,
'w'
)
t.add(
'/test1/a.py'
,arcname
=
'a.bak'
)
t.add(
'/test1/b.py'
,arcname
=
'b.bak'
)
t.close()
# 解压
t
=
tarfile.
open
(
'/tmp/egon.tar'
,
'r'
)
t.extractall(
'/egon'
)
t.close()
|
10、xml模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json功能差不多,但json使用起来更简单,由于比json出现的早,至今很多传统公司如金融行业的很多系统的接口还主要是xml
xml是通过<>节点(标签)来区别数据结构的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?
xml
version
=
"1.0"
?>
<
data
>
<
country
name
=
"Liechtenstein"
>
<
rank
updated
=
"yes"
>2</
rank
>
<
year
>2008</
year
>
<
gdppc
>141100</
gdppc
>
<
neighbor
name
=
"Austria"
direction
=
"E"
/>
<
neighbor
name
=
"Switzerland"
direction
=
"W"
/>
</
country
>
<
country
name
=
"Singapore"
>
<
rank
updated
=
"yes"
>5</
rank
>
<
year
>2011</
year
>
<
gdppc
>59900</
gdppc
>
<
neighbor
name
=
"Malaysia"
direction
=
"N"
/>
</
country
>
<
country
name
=
"Panama"
>
<
rank
updated
=
"yes"
>69</
rank
>
<
year
>2011</
year
>
<
gdppc
>13600</
gdppc
>
<
neighbor
name
=
"Costa Rica"
direction
=
"W"
/>
<
neighbor
name
=
"Colombia"
direction
=
"E"
/>
</
country
>
</
data
>
|
对xml进行操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import
xml.etree.ElementTree as ET
#导入模块方法
tree
=
ET.parse(
"xmltest.xml"
)
root
=
tree.getroot()
print
(root.tag)
#遍历xml文档
for
child
in
root:
print
(
'========>'
,child.tag,child.attrib,child.attrib[
'name'
])
fori
in
child:
print
(i.tag,i.attrib,i.text)
#只遍历year 节点
for
node
in
root.
iter
(
'year'
):
print
(node.tag,node.text)
#---------------------------------------
import
xml.etree.ElementTree as ET
tree
=
ET.parse(
"xmltest.xml"
)
root
=
tree.getroot()
#修改
for
node
in
root.
iter
(
'year'
):
new_year
=
int
(node.text)
+
1
node.text
=
str
(new_year)
node.
set
(
'updated'
,
'yes'
)
node.
set
(
'version'
,
'1.0'
)
tree.write(
'test.xml'
)
#删除node
for
country
in
root.findall(
'country'
):
rank
=
int
(country.find(
'rank'
).text)
ifrank >
50
:
root.remove(country)
tree.write(
'output.xml'
)
|
11、configparser模块
主要用来解析配置文件
配置文件为以下格式:
[section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31
[section2]
k1 = v1
操作方法如下:
import configparser # 导入模块
config=configparser.ConfigParser() #使用ConfigParser方法得到一个对象赋值给config
查看标题:
config.sections()
查看标题section1下所有key=value的key
config.options('section1')
查看标题section1下所有key=value的(key,value)格式
config.items('section1')
查看标题section1下user的值,字符串格式
config.get('section1','user')
查看标题section1下age的值,整数格式
val1=config.getint('section1','age')
查看标题section1下is_admin的值,布尔值格式
config.getboolean('section1','is_admin')
查看标题section1下salary的值,浮点型格式
config.getfloat('section1','salary')
删除整个标题section2
config.remove_section('section2')
删除标题section1下的某个k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')
判断是否存在某个标题
config.has_section('section1')
判断标题section1下是否有user
config.has_option('section1','user')
添加一个标题
config.add_section('egon')
在标题egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #报错,必须是字符串
最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))
12、hashlib模块
hash:一种算法 ,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
三个特点:
1.内容相同则hash运算结果相同,内容稍微改变则hash值则变
2.不可逆推
3.相同算法:无论校验多长的数据,得到的哈希值长度固定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
hashlib
m
=
hashlib.md5()
# m=hashlib.sha256()
m.update(
'hello'
.encode(
'utf8'
))
print
(m.hexdigest())
#5d41402abc4b2a76b9719d911017c592
m.update(
'alvin'
.encode(
'utf8'
))
print
(m.hexdigest())
#92a7e713c30abbb0319fa07da2a5c4af
m2
=
hashlib.md5()
m2.update(
'helloalvin'
.encode(
'utf8'
))
print
(m2.hexdigest())
#92a7e713c30abbb0319fa07da2a5c4af
'''
注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
但是update多次为校验大文件提供了可能。
'''
|
以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
import
hashlib
# ######## 256 ########
hash
=
hashlib.sha256(
'898oaFs09f'
.encode(
'utf8'
))
hash
.update(
'alvin'
.encode(
'utf8'
))
print
(
hash
.hexdigest())
#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
import
hashlib
passwds
=
[
'alex3714'
,
'alex1313'
,
'alex94139413'
,
'alex123456'
,
'123456alex'
,
'a123lex'
,
]
def
make_passwd_dic(passwds):
dic
=
{}
for
passwd inpasswds:
m
=
hashlib.md5()
m.update(passwd.encode(
'utf-8'
))
dic[passwd]
=
m.hexdigest()
return
dic
def
break_code(cryptograph,passwd_dic):
for
k,v inpasswd_dic.items():
if
v
=
=
cryptograph:
print
(
'密码是===>\033[46m%s\033[0m'
%
k)
cryptograph
=
'aee949757a2e698417463d47acac93df'
break_code(cryptograph,make_passwd_dic(passwds))
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密:
import
hmac
h
=
hmac.new(
'alvin'
.encode(
'utf8'
))
h.update(
'hello'
.encode(
'utf8'
))
print
(h.hexdigest())
#320df9832eab4c038b6c1d7ed73a5940
#要想保证hmac最终结果一致,必须保证:
#1:hmac.new括号内指定的初始key一样
#2:无论update多少次,校验的内容累加到一起是一样的内容
import
hmac
h1
=
hmac.new(b
'egon'
)
h1.update(b
'hello'
)
h1.update(b
'world'
)
print
(h1.hexdigest())
h2
=
hmac.new(b
'egon'
)
h2.update(b
'helloworld'
)
print
(h2.hexdigest())
h3
=
hmac.new(b
'egonhelloworld'
)
print
(h3.hexdigest())
'''
f1bf38d054691688f89dcd34ac3c27f2
f1bf38d054691688f89dcd34ac3c27f2
bcca84edd9eeb86f30539922b28f3981
'''
|
5.subprocess模块
在python解释器中开启一个子进程执行shell命令
stdout 标准正确输出 # 输出内容为bytes类型,如果在windows输出需要解码为decode(‘gbk’),linux解码为decode(‘utf-8’)
stderr 标准错误输出
stdin 标准输入
shell=True 使用shell命令
subprocess.PIPE 把输出结果放到管道
res1=subprocess.Popen('ls/Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE)
# 先列出桌面上的文件
subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,stdout=subprocess.PIPE)
# 把上面的数据交给这条命令作为输入结果,过滤以txt结尾的文件