1. 模块
在python中一个文件可以被看成一个独立模块,而包对应着文件夹,模块把python代码分成一些有组织的代码段,通过导入的方式实现代码重用。
1.1 模块搜索路径
导入模块时,是按照sys.path变量的值搜索模块,sys.path的值是包含每一个独立路径的列表,包含当前目录、python安装目录、PYTHONPATH环境变量,搜索顺序按照路径在列表中的顺序(一般当前目录优先级最高)。
1 >>>import sys2 >>>sys.path3 ['', 'E:\\Python27\\Lib\\idlelib', 'C:\\windows\\system32\\python27.zip', 'E:\\Python27\\DLLs', 'E:\\Python27\\lib', 'E:\\Python27\\lib\\plat-win', 'E:\\Python27\\lib\\lib-tk', 'E:\\Python27', 'E:\\Python27\\lib\\site-packages']
1.2 导入模块
1.2.1 使用import语句导入模块
有下面两种方式
import module1
import module2
import module3
import module1,module2,module3
这两种方式的效果是一样的,但是第一种可读性比第二种好,推荐按照下面的顺序导入模块,并且一般在文件首部导入所有的模块
python标准库
第三方模块
应用程序自定义模块
也可以在函数内部导入模块,这样被导入的模块作用域是局部的
1.2.2 使用from-import语句导入模块的属性
单行导入
1 from module import name1,name2,name3
多行导入
from module import name1,name2,\
name3
导入全部属性(由于容易覆盖当前名称空间中现有的名字,所以一般不推荐使用,适合模块中变量名很长并且变量很多的情况)
1 from module import *
如果你不想某个模块的属性被以上方法导入,可以给该属性名称前加一个下划线(_test),如果需要取消隐藏,可以显示的导入该属性(from module import _test)
1.2.3 扩展的import语句
使用自定义的名称替换模块的原始名称
import simplejson as json
模块被导入时,加载的时候模块顶层代码会被执行,如:设定全局变量、类和函数的声明等,所以应该把代码尽量封装到类和函数中。一个模块无论被导入多少次,只加载一次,可以防止多次导入时代码被多次执行。
1.2.4 重新导入模块reroad
1)import
import作用:导入/引入一个python标准模块,其中包括.py文件、带有__init__.py文件的目录。
import module_name[,module1,...]
from module import *|child[,child1,...]
说明:多次重复使用import语句时,不会重新加载被指定的模块,只是把对该模块的内存地址给引用到本地变量环境。
a.py
#!/usr/bin/env python
#encoding: utf-8
import os
print 'in a',id(os)
m.py
#!/usr/bin/env python
#encoding: utf-8
import a #第一次会打印a里面的语句
import os #再次导入os后,其内存地址和a里面的是一样的,因此这里只是对os的本地引用
print 'in c',id(os)
import a #第二次不会打印a里面的语句,因为没有重新加载
#结果
in a 23124144
in c 23124144
2)reroad
作用:对已经加载的模块进行重新加载,一般用于原模块有变化等特殊情况,reload前该模块必须已经import过。
import os
reload(os)
说明:reload会重新加载已加载的模块,但原来已经使用的实例还是会使用旧的模块,而新生产的实例会使用新的模块;
reload后还是用原来的内存地址;
不能支持from。。import。。格式的模块进行重新加载。
1 a.py2 #!/usr/bin/env python3 #encoding: utf-8
4 import os5 print 'in a',id(os)6
7 m.py8 #!/usr/bin/env python9 #encoding: utf-8
10 import a #第一次import会打印a里面的语句11 print id(a) #原来a的内存地址12 reload(a) #第二次reload还会打印a里面的语句,因为有重新加载13 print id(a) #reload后a的内存地址,和原来一样
#结果
>>>
in a 23058608
29617680
in a 23058608
29617680
>>>
2. 包
包是另外一种模块,可以包含其他模块;
模块存储在文件中时(拓展名.py),包就是模块所在的目录;
包必须包括一个__init__.py的文件(模块),若将其作为普通模块导入文件内容就是包的内容
#名为constants的包,文件constants/__init__.py包括语句PI=3.14
import constants
print constants.PI
为了将模块放置在包内,直接把模块放在包目录内即可:
3. 标准库
3.1 sys
sys模块能够访问与Python解释器紧密联系的变量和函数,下面是 sys 模块中一些常用的函数和变量:
argv 命令行参数,包括脚本名称
exit([arg]) 退出当前程序,可选参数给定的返回值或错误信息
modules 隐射模块名字到载入模块的字典
path 查看模块所在目录的目录名列表
platform 类似sunos5或win32平台标识符
stdin 标准输入流——一个类文件(file-like)对象
stdout 标准输出流——一个类文件对象
stderr 标准错误流——一个类文件对象
1)sys.argv
下面的示例通过argv获取命令行参数,然后将其反转:
import sys
args = sys.argv[1:] # 跳过第一个元素(脚本名称)
args.reverse()
print ' '.join(args)
2)sys.platform
我们想实现一个清除终端,linux下用clear, windows下用cls
ostype=sys.platform
if ostype==”linux” or ostype==”linux2”:
Cmd=”clear”
else:
Cmd=”cls”
3)sys.exit(n)
执行至主程序的末尾时,解释器会自动退出. 但是如果需要中途退出程序, 你可以调用sys.exit 函数, 它带有一个可选的整数参数返回给调用它的程序.这意味着你可以在主程序中捕获对sys.exit 的调用。(注:0是正常退出,其他为不正常,可抛异常事件供捕获!)
1 import sys2
3 def exitfunc(value):4 '''Clear function'''
5 print value6 sys.exit(0)7
8 print "hello"
9
10 try:11 sys.exit(1)12 except SystemExit,value:13 exitfunc(value)14
15 print "come?"
16
17 #输出结果:18 [root@databak scripts]# python test.py19 hello20 1
4)sys.stdin,sys.stdout,sys.stderr
stdin , stdout , 以及stderr 变量包含与标准I/O 流对应的流对象. 如果需要更好地控制输出,而print 不能满足你的要求, 它们就是你所需要的. 你也可以替换它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或者以非标准的方式处理它们
sys.stdout 与 print
当我们在 Python 中打印对象调用 print obj 时候,事实上是调用了 sys.stdout.write(obj+'\n');
print 将你需要的内容打印到了控制台,然后追加了一个换行符;
print 会调用 sys.stdout 的 write 方法
#等价
sys.stdout.write('hello'+'\n')
print 'hello'
sys.stdin 与 raw_input
当我们用 raw_input('Input promption: ') 时,事实上是先把提示信息输出,然后捕获输入
#等价
hi=raw_input('hello? ')
print 'hello? ', #comma to stay in the same line
hi=sys.stdin.readline()[:-1] # -1 to discard the '\n' in input stream
从控制台重定向到文件
原始的 sys.stdout 指向控制台;
如果把文件的对象的引用赋给 sys.stdout,那么 print 调用的就是文件对象的 write 方法;
f_handler=open('out.log', 'w')
sys.stdout=f_handler
print 'hello'
# this hello can't be viewed on concole
# this hello is in file out.log
记住,如果你还想在控制台打印一些东西的话,最好先将原始的控制台对象引用保存下来,向文件中打印之后再恢复 sys.stdout
__console__=sys.stdout
# redirection start
# ...
# redirection end
sys.stdout=__console__
同时重定向到控制台和文件
希望打印的内容一方面输出到控制台,另一方面输出到文件作为日志保存
1 import sys2
3 class__redirection__:4
5 def __init__(self):6 self.buff=''
7 self.__console__=sys.stdout8
9 def write(self, output_stream):10 self.buff+=output_stream11
12 def to_console(self):13 sys.stdout=self.__console__14 print self.buff15
16 def to_file(self, file_path):17 f=open(file_path,'w')18 sys.stdout=f19 print self.buff20 f.close()21
22 def flush(self):23 self.buff=''
24
25 def reset(self):26 sys.stdout=self.__console__27
28
29 if __name__=="__main__":30 # redirection31 r_obj=__redirection__()32 sys.stdout=r_obj33
34 # getoutput stream35 print 'hello'
36 print 'there'
37
38 # redirect to console39 r_obj.to_console()40
41 # redirect to file42 r_obj.to_file('out.log')43
44 # flush buffer45 r_obj.flush()46
47 # reset48 r_obj.reset()
3.2 os模块
os模块提供了很多访问操作系统服务的功能。下面是一些常用的函数和变量:
environ 对环境变量进行映射
system(command) 在子shell中执行操作系统命令
sep 路径中的分隔符
pathsep 分隔路径的分隔符
linesep 行分隔符('\n','\r','\r\n')
urandom(n) 返回n自己的加密强随机数
1)下面示例通过 environ 变量来查询环境变量中的 path 变量值:
import os
# C:\Perl64\site\bin;C:\Perl64\...
print os.environ['path']
2)根据不同的操作系统返回对于的路径分隔符:
# -- coding: utf-8 --
import os
# 返回操作系统中的路径分隔符
# windows:'\'
# UNIX/LINUX:'/'
# Mac OS:':'
print os.sep
3.3 fileinput模块
fileinput 模块可以轻松的遍历文本文件的所有行。下面是 fileinput 模块中重要的函数:
input([files[, inplace[. backup]]) 便于遍历多个输入流中的行
filename() 返回当前文件的名称
filelineno() 返回当前处理文件当前(累计)行数
isfirstline() 检查当前行是否是文件的第一行
isstdin() 检查最后一行是否来自sys.stdin
nextfile() 关闭当前文件,移动到下一个文件
close() 关闭序列
input函数:
格式:fileinput.input([files[, inplace[, backup[, bufsize[, mode[, openhook]]]]]])
默认格式:fileinput.input (files=None, inplace=False, backup='', bufsize=0, mode='r', openhook=None)
说明:
1)读取一个文件所有行
1 >>>import fileinput2 >>> for line in fileinput.input('data.txt'):3 print line,4 #输出结果5 Python6 Java7 C/C++
8 Shell9
10
11 命令行方式:12 #test.py13 import fileinput14
15 for line infileinput.input():16 print fileinput.filename(),'|','Line Number:',fileinput.lineno(),'|:',line17
18 c:>python test.py data.txt19 data.txt | Line Number: 1 |: Python20 data.txt | Line Number: 2 |: Java21 data.txt | Line Number: 3 |: C/C++
22 data.txt | Line Number: 4 |: Shell
2)对多文件操作,并原地修改内容
1 #test.py2 #---样本文件---
3 c:Python27>type 1.txt4 first5 second6
7 c:Python27>type 2.txt8 third9 fourth10 #---样本文件---
11 import fileinput12
13 def process(line):14 return line.rstrip() + 'line' #rstrip()用来在字符串末尾删除某个字符,lstrip()用来在字符串首部的删除某个字符,strip()用来在字符串的首尾删除某个字符
15
16 for line in fileinput.input(['1.txt','2.txt'],inplace=1):17 print process(line)18
19 #---结果输出---
20 c:Python27>type 1.txt21 first line22 second line23
24 c:Python27>type 2.txt25 third line26 fourth line27 #---结果输出---
28
29
30
31 命令行方式:32 #test.py33 import fileinput34
35 def process(line):36 return line.rstrip() + 'line'
37
38 for line in fileinput.input(inplace =True):39 print process(line)40
41 #执行命令42 c:Python27>python test.py 1.txt 2.txt43
3)实现文件内容替换,并将原文件备份
1 #样本文件:2 #data.txt3 Python4 Java5 C/C++
6 Shell7
8 #FileName: test.py9 import fileinput10
11 for line in fileinput.input('data.txt',backup='.bak',inplace=1):12 print line.rstrip().replace('Python','Perl') #或者print line.replace('Python','Perl'),13
14 #最后结果:15 #data.txt16 Perl17 Java18 C/C++
19 Shell20 #并生成:21 #data.txt.bak文件
4)文件的简单处理
1 #FileName: test.py2 #!/usr/bin/env python3 #encoding: utf-8
4 import sys5 import fileinput6
7 for line in fileinput.input(r'data.txt'):8 sys.stdout.write('=>')9 sys.stdout.write(line)
#结果
=>Perl
=>Java
=>C/C++
=>Shell
5)批处理文件
glob是python自己带的一个文件操作相关模块,内容也不多,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索,而且也支持通配符,*,?,[]这三个通配符,*代表0个或多个字符,?代表一个字符,[]匹配指定范围内的字符,如[0-9]匹配数字。
它的主要方法就是glob,该方法返回所有匹配的文件路径列表,该方法需要一个参数用来指定匹配的路径字符串(本字符串可以为绝对路径也可以为相对路径),其返回的文件名只包括当前目录里的文件名,不包括子文件夹里的文件。比如:glob.glob(r'c:\*.txt'),获得C盘下的所有txt文件
1 #---测试文件: test.txt test1.txt test2.txt test3.txt---
2 #---脚本文件: test.py---
3 import fileinput4 import glob5
6 for line in fileinput.input(glob.glob(test*.txt)):7 iffileinput.isfirstline():8 print '-'*20, 'Reading %s...' % fileinput.filename(), '-'*20
9 print str(fileinput.lineno()) + ':' +line.upper(),10
11
12 #---输出结果:13 >>>
14 -------------------- Reading test.txt... --------------------
15 1: AAAAA16 2: BBBBB17 3: CCCCC18 4: DDDDD19 5: FFFFF20 -------------------- Reading test1.txt... --------------------
21 6: FIRST LINE22 7: SECOND LINE23 -------------------- Reading test2.txt... --------------------
24 8: THIRD LINE25 9: FOURTH LINE26 -------------------- Reading test3.txt... --------------------
27 10: THIS IS LINE 1
28 11: THIS IS LINE 2
29 12: THIS IS LINE 3
30 13: THIS IS LINE 4
6)利用fileinput和re做日志分析:提取所有含日期的行
1 #--样本文件--
2 aaa3 1970-01-01 13:45:30 Error: ****Due to System Disk spacke not enough...4 bbb5 1970-01-02 10:20:30 Error: ****Due to System Out of Memory...6 ccc7
8 #---测试脚本---
9 import re10 import fileinput11 import sys12
13 pattern = 'd{4}-d{2}-d{2} d{2}:d{2}:d{2}'
14
15 for line in fileinput.input('error.log',backup='.bak',inplace=1):16 ifre.search(pattern,line):17 sys.stdout.write(=>)18 sys.stdout.write(line)19
20 #---测试结果---
21 => 1970-01-01 13:45:30 Error: ****Due to System Disk spacke not enough...22 => 1970-01-02 10:20:30 Error: **** Due to System Out of Memory...
7)利用fileinput和re做日志分析:提取符合条件的电话号码
1 #---样本文件: phone.txt---
2 010-110-12345
3 800-333-1234
4 010-99999999
5 05718888888
6 021-88888888
7
8 #---测试脚本: test.py---
9 import re10 import fileinput11
12 pattern = '[010|021]-d{8}' #提取区号为010或021电话号码,格式:010-12345678
13
14 for line in fileinput.input('phone.txt'):15 ifre.search(pattern,line):16 print '=' * 50
17 print 'Filename:'+ fileinput.filename()+'| Line Number:'+str(fileinput.lineno())+'|'+line,18
19 #---输出结果:---
20 >>>
21 ==================================================
22 Filename:phone.txt | Line Number:3 | 010-99999999
23 ==================================================
24 Filename:phone.txt | Line Number:5 | 021-88888888
25 >>>
3.4 集合,堆和双端队列
集合
集合(set)在Python 2.3 引入。Set类位于 sets 模块中。使用集合不需要导入,直接使用即可:
print set(range(10))
# set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
集合是由序列(或者其他可迭代对象)构建的,它们主要用于检查成员资格,因此副本是被忽略的:
print set([0, 1, 2, 3, 1, 2, 3])
# set([0, 1, 2, 3])
除了检查成员资格,还可以使用标准的集合操作,如:并集和交集,既可以使用方法,也可以直接使用运算操作符:
1 a = set([1,2,3])
2 b = set([2,3,4,5])
3 print a.union(b) # set([1, 2, 3, 4, 5])
4 print a | b # set([1, 2, 3, 4, 5])
5
6 c = a & b
7 print c.issubset(a) # True
8
9 print c <= a # True
10 print c.intersection(b) # set([2, 3])
11
12 print a & b # set([2, 3])
13 print a.difference(b) # set([1])
14
15 print a - b # set([1])
16 print a.symmetric_difference(b) # set([1, 4, 5])
17
18 print a ^ b # set([1, 4, 5])
19 print a.copy() # set([1, 2, 3])
20 print a.copy() is a # False
集合是可变的,且本身只能包含不可变值,但是一个包含集合的集合是常见的,这时,我们只需使用 frozenset 类型对集合进行包装即可,frozenset 构造函数可以创建给定集合的一个副本:
a = set([1,2,3])
b = set([2,3,4,5])
a.add(frozenset(b))
print a # set([1, 2, 3, frozenset([2, 3, 4, 5])])
堆
堆(heap)是优先队列的一种。使用优先队列能够以任意顺序增加对象,并且能在任何时间(可能在增加对象的同时)找到(也可能是移除)最小的元素(比列表的min方法更有效率)。在Python中没有独立的堆类型——只有一个包含一些堆操作的模块,该模块是 heapq,包含了六个函数:
heappush(heap,x) 将x入堆
heappop(heap) 将堆中最小的元素弹出
heapify(heap) 将heap属性强制应用到任意一个列表
heapreplace(heap,x) 将堆中最小的元素弹出,同时将x入堆
nlargest(n,iter) 返回iter中第n大的元素
nsmallest(n,iter) 返回iter中第n小的元素
heappush 函数用于增加堆的项,如下:
1 from heapq import *
2 from random import shuffle
3
4 data = range(10)
5 shuffle(data) # shuffle() 方法将序列的所有元素随机排序
6 heap = []
7 for n in data:
8 heappush(heap,n)
9
10 print heap # [0, 2, 1, 4, 3, 7, 5, 9, 6, 8]
11
12 heappush(heap,0.5)
13 print heap # [0, 0.5, 5, 3, 1, 6, 7, 9, 8, 4, 2]
堆元素的排序是有规则的:位于i位置上的元素总比i//2位置处的元素大(或者说位置i处的元素总比2i以及21+1位置处的元素小)
双端队列
双端队列(Double-ended queue)在需要按照元素增加的顺序来移除元素时非常有用。双端队列通过可迭代对象(比如集合)创建:
1 from collections import deque
2
3 q = deque(range(5))
4 q.append(5)
5 q.appendleft(6)
6
7 print q # deque([6, 0, 1, 2, 3, 4, 5])
8 print q.pop() # 5
9
10 q.rotate(3)
11 print q # deque([2, 3, 4, 6, 0, 1])
12
13 q.rotate(-1)
14 print q # deque([3, 4, 6, 0, 1, 2])
3.5 time模块
time 模块所包含的函数能够实现以下功能:获取当前时间、操作时间和日期、从字符串读取时间以及格式化时间字符串。日期可以使用实数(从“新纪元”的1月1日0 点开始计算到现在的秒数,新纪元是一个与平台相关的年份,对于UNIX来说是1970年),或者是包含9个整数的元组,它们分别表示下面的含义:
(2008,1,21,12,2,56,0,21,0) # 年、月、日、时、分、秒、周、儒日历、夏令时
下面是 time 模块最常用的函数:
asctime([tuple]) 将时间元组转换为字符串
localtime([secs]) 将秒数转换为日期元组,以本地时间为准(与mktime相反)
mktime(tuple) 将时间元组转换为新纪元开始计算的秒数
sleep(secs) 休眠 secs秒
strptime(string[, format]) 将字符串解析为时间元组
time() 当前时间(新纪元开始后的秒数,以UTC为准)
3.6 random模块
random 模块包含返回随机数(伪随机数)的函数,下面是 random 模块的重要函数:
random() 返回 0 ≤ n < 1 之间的随机实数n,其中 0 < n ≤ 1
getrandbits(n) 以长整型形式返回n个随机数
uniform(a,b) 返回随机实数n,其中 a ≤ n < b
randrange([start],stop,[step]) 返回range(start,stop,step)中的随机数
choice(seq) 从序列seq中返回随意元素
shuffle(seq[, random]) 原地指定序列seq
sample(seq,n) 从序列seq中选择n个随机且独立的元素
下面的示例可以随机产生2008 ~ 2009 之间的随机一天:
from random import *
from time import *
date1 = (2008,1,1,0,0,0,-1,-1,-1)
time1 = mktime(date1)
date2 = (2009,1,1,0,0,0,-1,-1,-1)
time2 = mktime(date2)
random_time = uniform(time1,time2)
print asctime(localtime(random_time))
3.7 shelve模块
使用 shelve 模块提供了一个简单的文件存储方案。我们可以将一个对象持久化到文件中,如下:
1 import sys, shelve
2
3 def main():
4 data = shelve.open("D:\\data.dat")
5 employee = {}
6 employee['name'] = 'sunshine'
7 employee['email'] = '[email protected]'
8 pid = '1'
9 try:
10 data[pid] = employee
11 finally:
12 data.close()
13
14 if __name__ == '__main__': main()
持久化之后,可以再次读取文件中的内容:
import sys, shelve
def main():
pid = '1'
data = shelve.open("D:\\data.dat")
print data[pid] # {'name': 'sunshine', 'email': '[email protected]'}
if __name__ == '__main__': main()
3.8 re模块(正则表达式)
3.8.1 元字符
常用元字符
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束^匹配行的开始
$ 匹配行的结束
常用反义元字符
代码 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
常用重复限定符
代码 说明*重复零次或更多次+重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
正则表达式(可以称为REs,regex,regex pattens)是一个小巧的,高度专业化的编程语言,它内嵌于python开发语言中,可通过re模块使用。正则表达式的pattern可以被编译成一系列的字节码,然后用C编写的引擎执行。下面简单介绍下正则表达式的语法
正则表达式包含一个元字符(metacharacter)的列表,列表值如下: . ^ $ * + ? { [ ] \ | ( )
1).元字符([ ]),它用来指定一个character class。所谓character classes就是你想要匹配的字符(character)的集合.字符(character)可以单个的列出,也可以通过"-"来分隔 两个字符来表示一 个范围。例如,[abc]匹配a,b或者c当中任意一个字符,[abc]也可以用字符区间来表示---[a-c].如果想要匹配单个大写字母,你可以用 [A-Z]。
元字符(metacharacters)在character class里面不起作用,如[akm$]将匹配"a","k","m","$"中的任意一个字符。在这里元字符(metacharacter)"$"就是一个普通字符。
2).元字符[^]. 你可以用补集来匹配不在区间范围内的字符。其做法是把"^"作为类别的首个字符;其它地方的"^"只会简单匹配 "^"字符本身。例如,[^5] 将匹配除 "5" 之外 的任意字符。同时,在[ ]外,元字符^表示匹配字符串的开始,如"^ab+"表示以ab开头的字符串。
>>> m=re.search("^ab+","asdfabbbb")>>> printm
None>>> m=re.search("ab+","asdfabbbb")>>> printm<_sre.SRE_Match object at 0x011B1988>
>>> printm.group()
abbbb
上例不能用re.match,因为match匹配字符串的开始,我们无法验证元字符"^"是否代表字符串的开始位置。
>>> m=re.match("^ab+","asdfabbbb")>>> printm
None>>> m=re.match("ab+","asdfabbbb")>>> printm
None
验证在元字符[]中,"^"在不同位置所代表的意义。
>>> re.search("[^abc]","abcd") #"^"在首字符表示取反,即abc之外的任意字符。
<_sre.SRE_Match object at 0x011B19F8>
>>> m=re.search("[^abc]","abcd")>>>m.group()'d'
>>> m=re.search("[abc^]","^") #如果"^"在[ ]中不是首字符,那么那就是一个普通字符
>>>m.group()'^'
3). 元字符(\),元字符backslash。做为 Python 中的字符串字母,反斜杠后面可以加不同的字符以表示不同特殊意义。它也可以用于取消所有的元字符,这样你 就可以在模式 中匹配它们了。例如,如果你需要匹配字符 "[" 或 "\",你可以在它们之前用反斜杠来取消它们的特殊意义: \[ 或 \\
4).元字符($)匹配字符串的结尾或者字符串结尾的换行之前。(在MULTILINE模式下,"$"也匹配换行之前)。正则表达式"foo"既匹配"foo"又匹配"foobar",而"foo$"仅仅匹 配"foo".
>>> re.findall("foo.$","foo1\nfoo2\n")#匹配字符串的结尾的换行符之前。
['foo2']>>> re.findall("foo.$","foo1\nfoo2\n",re.MULTILINE)
['foo1', 'foo2']>>> m=re.search("foo.$","foo1\nfoo2\n")>>>m<_sre.SRE_Match object at 0x00A27170>
>>>m.group()'foo2'
>>> m=re.search("foo.$","foo1\nfoo2\n",re.MULTILINE)>>>m.group()'foo1'
5).元字符(*),匹配0个或多个
6).元字符(?),匹配一个或者0个
7).元字符(+), 匹配一个或者多个
8).元字符(|), 表示"或",如A|B,其中A,B为正则表达式,表示匹配A或者B
9).元字符({})。
{m},用来表示前面正则表达式的m次copy,如"a{5}",表示匹配5个”a”,即"aaaaa"
>>> re.findall("a{5}","aaaaaaaaaa")
['aaaaa', 'aaaaa']>>> re.findall("a{5}","aaaaaaaaa")
['aaaaa']
{m.n}用来表示前面正则表达式的m到n次copy,尝试匹配尽可能多的copy
>>> re.findall("a{2,4}","aaaaaaaa")
['aaaa', 'aaaa']
通过上面的例子,可以看到{m,n},正则表达式优先匹配n,而不是m,因为结果不是["aa","aa","aa","aa"]
>>> re.findall("a{2,4}","aaaaaaaa")
['aaaa', 'aaaa']
{m,n}? 用来表示前面正则表达式的m到n次copy,尝试匹配尽可能少的copy
>>> re.findall("a{2,4}?","aaaaaaaa")
['aa', 'aa', 'aa', 'aa']
10).元字符( "( )" ),用来表示一个group的开始和结束。
比较常用的有(REs),(?PREs),这是无名称的组和有名称的group,有名称的group,可以通过matchObject.group(name).获取匹配的group,而无名称的 group可以通过从1开始的group序号来获取匹配的组,如matchObject.group(1)。
11).元字符(.)
元字符“.”在默认模式下,匹配除换行符外的所有字符。在DOTALL模式下,匹配所有字符,包括换行符。
>>> importre>>> re.match(".","\n")>>> m=re.match(".","\n")>>> printm
None>>> m=re.match(".","\n",re.DOTALL)>>> printm<_sre.SRE_Match object at 0x00C2CE20>
>>>m.group()'\n'
3.8.2 re模块方法
re.match
re.match 尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
m = re.match(r"(\w+)\s", text)
if m:
print m.group(0), '\n', m.group(1)
else:
print 'not match'
re.match的函数原型为:re.match(pattern, string, flags)
第一个参数是正则表达式,这里为"(\w+)\s",如果匹配成功,则返回一个Match,否则返回一个None;
第二个参数表示要匹配的字符串;
第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
re.search
re.search函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
m = re.search(r'\shan(ds)ome\s', text)
if m:
print m.group(0), m.group(1)
else:
print 'not search'
re.search的函数原型为: re.search(pattern, string, flags) ,每个参数的含意与re.match一样。
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
而re.search匹配整个字符串,直到找到一个匹配。
re.sub
re.sub用于替换字符串中的匹配项。下面一个例子将字符串中的空格 ' ' 替换成 '-' :
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
print re.sub(r'\s+', '-', text)
re.sub的函数原型为:re.sub(pattern, repl, string, count)
其中第二个函数是替换后的字符串;本例中为'-'
第四个参数指替换个数。默认为0,表示每个匹配项都替换。
re.sub还允许使用函数对匹配项的替换进行复杂的处理。如:re.sub(r'\s', lambda m: '[' + m.group(0) + ']', text, 0);将字符串中的空格' '替换为'[ ]'。
re.split
可以使用re.split来分割字符串,如:re.split(r'\s+', text);将字符串按空格分割成一个单词列表。
re.findall
re.findall可以获取字符串中所有匹配的字符串。如:re.findall(r'\w*oo\w*', text);获取字符串中,包含'oo'的所有单词。
re.compile
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式对象的一个例子:
importre
text= "JGood is a handsome boy, he is cool, clever, and so on..."regex= re.compile(r'\w*oo\w*')print regex.findall(text) #查找所有包含'oo'的单词
print regex.sub(lambda m: '[' + m.group(0) + ']', text) #将字符串中含有'oo'的单词用[]括起来。
3.8.3 补充
1. 正则表达式的基本概念
1. 1 通配符
点号( . )可以匹配换行符之外的任何单个字符,被称之为通配符。
1.2 特殊字符转义
将有特殊含义的字符作为普通字符使用时需要进行转义。例如想要匹配 python.org时需要将表达式写为: python\\.org 才行。
为什么使用两个反斜线?
这是为了通过解释器进行转义,需要进行两个级别的转义:1.通过解释器的转义;2.通过 re 模块转义。如果不想使用两个反斜线,可以考虑使用原始字符串,如:r'python\.org'。
1.3 字符集
字符集是在中括号( [] )中包含字符串。字符集可以匹配它所包含的任意字符。即'[pj]ython'可以匹配 python 和 jython 。
使用范围
可以使用范围,如 '[a-z]' 可以匹配 a 到 z 的任意一个字符。'a-zA-Z0-9' 可以匹配任意大小写的一个字母或数字。
反转字符集
我们也可以对字符集进行反转,比如 '[^abc]' 匹配除了a、b和c之外的任何字符。
字符集中的特殊字符
特殊字符在模式中做文本字符,而不是正则表达式运算符的话需要对其进行转义。但是在字符集中并不需要,只有以三种情况下,需要将特殊字符作为普通文本使用时,需要对字符进行转义:
^ 脱字符作为字符集的开头
] 右中括号作为字符集的开头
- 横线(字符范围)作为字符集的开头
1.4 选择符合子模式
管道符号( | )是用于选择项的特殊字符。例如: 'python|ruby' 匹配python和ruby这两个单词。
子模式(subparttern)是指:使用圆括号将选择项括起来。例如 'p(ython|erl)' 匹配python和perl。
1.5 可选项和重复子模式
在子模式后面加上一个问号,它就变成了一个可选项,例如:
r'(http://)?(www\.)?python\.org$'
上面的模式只能匹配下面的字符串:
'http://www.python.org'
'http://python.org'
'www.python.org'
'python.org'
问号表示子模式可以出现一次或者根本不出现,下面的运算符允许子模式重复多次:
(pattern)*: 允许模式重复0次或多次
(pattern)+: 允许模式出现一次或多次
(pattern){m-n}: 允许模式重复m~n次
1.6 字符串的开始和结尾
使用 ^ 脱字符标记字符串开始;使用美元符号 $ 标识字符串的结尾。如:
'^Python$'
2. re 模块
re 模块包含了很多操作正则表达式的函数,以下是其中最常用的函数:
1 compile(pattern[, flags]) 根据包含正则表达式的字符串创建模式对象
2 search(pattern, string[, flags]) 在字符串中寻找模式
3 match(pattern, string[, flags]) 在字符串的开始处匹配模式
4 split(pattern, string[, maxsplit=0]) 根据模式的匹配项来分割字符串
5 findall(pattern, string) 列出字符串中模式的所有匹配项
6 sub(pat, repl, string[, count=0]) 将字符串中所有pat的匹配项用repl替换
7 escape(string) 将字符串中所有特殊正则表达式字符转义
下面是这些函数的的简单示例:
1 # --coding: utf-8 --
2 import re
3
4 # search
5 pattern = r'(http://)?(www\.)?python\.org$'
6 string = 'python.org'
7 if re.search(pattern,string):
8 print 'found it'
9
10 # match
11 text = 'alpha,beta,,,,,,gamma delta'
12 pattern = '[,]+' # 注意+号
13 print re.split(pattern,text) # ['alpha', 'beta', 'gamma delta']
14
15 # findall
16 pattern = '[a-zA-Z]+' # 匹配单词
17 text = '"Hm... Err -- are you sure?" he said, sounding insecure.'
18 # ['Hm', 'Err', 'are', 'you', 'sure', 'he', 'said', 'sounding', 'insecure']
19 print re.findall(pattern,text)
20
21 pattern = r'[.?\-",]' # 匹配标点符号
22 # ['"', '.', '.', '.', '-', '-', '?', '"', ',', '.']
23 print re.findall(pattern,text)
24
25 # sub
26 pattern = '{name}'
27 text = 'Dear {name}...'
28 print re.sub(pattern, 'Mr. Gumby', text) # Dear Mr. Gumby...
29
30 # escape
31 print re.escape('www.python.org') # www\.python\.org
32 print re.escape('But where is the ambiguity?') # But\ where\ is\ the\ ambiguity\?
2.1 匹配对象和组
当 re 模块中对字符串进行匹配的函数找到匹配项时,就会返回一个 MatchObject 对象。
组的概念
该对象包含了匹配模式的子字符串的信息,这些信息由组(group)构成。简而言之,组就是放置在圆括号内的子模式。组的序号取决于它左侧的括号数。组0就是整个模式。在下面的模式中:
'There (was a (wee) (cooper)) who (lived in Fyfe)'
包含这些组:
0 There was a wee cooper who lived in Fyfe
1 was a wee cooper
2 wee
3 cooper
4 lived in Fyfe
下面是 re 匹配对象的常用方法:
1 group([group1], ...]) 获取给定子模式(组)的匹配项
2 start([start]) 返回给定组匹配项的开始位置(返回结果是索引从0开始)
3 end([end]) 返回给定组匹配项的结束位置(返回结果是索引加1,和分片一样,不包括组的结束位置)
4 span([group]) 返回一个组的开始和结束位置
示例如下:
1 import re
2
3 m = re.match(r'www\.(.*)\..{3}','www.python.org')
4 print m.group(1) # python
5 print m.start(1) # 4
6 print m.end(1) # 10
7 print m.span(1) # (4, 10)
除了整体匹配以为(组0),只能使用99个组,即组的范围在1-99之间
2.2 使用re的替换函数
通过使用 re.sub 函数和组号的结合,还可以实现更加复杂的字符串提供功能,如下所示:
import re
emphasis_pattern = r'\*([^\*]+)\*'
# hello, world!
print re.sub(emphasis_pattern,r'\1','hello, *world*!')
贪婪模式和非贪婪模式
重复运算符默认是贪婪的( greedy),它会进行尽可能多的匹配。如下面的模式使用的就是贪婪模式:
1 import re
2
3 emphasis_pattern = r'\*(.+)\*'
4 text = '*This* is *it*'
5 # This* is *it
6 print re.sub(emphasis_pattern,r'\1',text)
非贪婪模式和贪婪模式相反,它会尽可能少的匹配。将重复运算符变成非贪婪模式只需要在其后加一个问号( ? )即可:
1 import re
2
3 emphasis_pattern = r'\*(.+?)\*'
4 text = '*This* is *it*'
5 # This is it
6 print re.sub(emphasis_pattern,r'\1',text)