python基础教程总结9——模块,包,标准库
1. 模块
在python中一个文件可以被看成一个独立模块,而包对应着文件夹,模块把python代码分成一些有组织的代码段,通过导入的方式实现代码重用。
1.1 模块搜索路径
导入模块时,是按照sys.path变量的值搜索模块,sys.path的值是包含每一个独立路径的列表,包含当前目录、python安装目录、PYTHONPATH环境变量,搜索顺序按照路径在列表中的顺序(一般当前目录优先级最高)。
1 >>> import sys 2 >>> sys.path 3 ['', '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
导入全部属性(由于容易覆盖当前名称空间中现有的名字,所以一般不推荐使用,适合模块中变量名很长并且变量很多的情况)
如果你不想某个模块的属性被以上方法导入,可以给该属性名称前加一个下划线(_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.py 2 #!/usr/bin/env python 3 #encoding: utf-8 4 import os 5 print 'in a',id(os) 6 7 m.py 8 #!/usr/bin/env python 9 #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. 标准库
可以查看Python 文档:http://docs.python.org/2/library/
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 sys 2 3 def exitfunc(value): 4 '''Clear function''' 5 print value 6 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.py 19 hello 20 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 sys 2 3 class __redirection__: 4 5 def __init__(self): 6 self.buff='' 7 self.__console__=sys.stdout 8 9 def write(self, output_stream): 10 self.buff+=output_stream 11 12 def to_console(self): 13 sys.stdout=self.__console__ 14 print self.buff 15 16 def to_file(self, file_path): 17 f=open(file_path,'w') 18 sys.stdout=f 19 print self.buff 20 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 # redirection 31 r_obj=__redirection__() 32 sys.stdout=r_obj 33 34 # get output stream 35 print 'hello' 36 print 'there' 37 38 # redirect to console 39 r_obj.to_console() 40 41 # redirect to file 42 r_obj.to_file('out.log') 43 44 # flush buffer 45 r_obj.flush() 46 47 # reset 48 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 fileinput 2 >>> for line in fileinput.input('data.txt'): 3 print line, 4 #输出结果 5 Python 6 Java 7 C/C++ 8 Shell 9 10 11 命令行方式: 12 #test.py 13 import fileinput 14 15 for line in fileinput.input(): 16 print fileinput.filename(),'|','Line Number:',fileinput.lineno(),'|: ',line 17 18 c:>python test.py data.txt 19 data.txt | Line Number: 1 |: Python 20 data.txt | Line Number: 2 |: Java 21 data.txt | Line Number: 3 |: C/C++ 22 data.txt | Line Number: 4 |: Shell
2)对多文件操作,并原地修改内容
1 #test.py 2 #---样本文件--- 3 c:Python27>type 1.txt 4 first 5 second 6 7 c:Python27>type 2.txt 8 third 9 fourth 10 #---样本文件--- 11 import fileinput 12 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.txt 21 first line 22 second line 23 24 c:Python27>type 2.txt 25 third line 26 fourth line 27 #---结果输出--- 28 29 30 31 命令行方式: 32 #test.py 33 import fileinput 34 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.txt 43
3)实现文件内容替换,并将原文件备份
1 #样本文件: 2 #data.txt 3 Python 4 Java 5 C/C++ 6 Shell 7 8 #FileName: test.py 9 import fileinput 10 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.txt 16 Perl 17 Java 18 C/C++ 19 Shell 20 #并生成: 21 #data.txt.bak文件
4)文件的简单处理
1 #FileName: test.py 2 #!/usr/bin/env python 3 #encoding: utf-8 4 import sys 5 import fileinput 6 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 fileinput 4 import glob 5 6 for line in fileinput.input(glob.glob(test*.txt)): 7 if fileinput.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: AAAAA 16 2: BBBBB 17 3: CCCCC 18 4: DDDDD 19 5: FFFFF 20 -------------------- Reading test1.txt... -------------------- 21 6: FIRST LINE 22 7: SECOND LINE 23 -------------------- Reading test2.txt... -------------------- 24 8: THIRD LINE 25 9: FOURTH LINE 26 -------------------- 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 aaa 3 1970-01-01 13:45:30 Error: **** Due to System Disk spacke not enough... 4 bbb 5 1970-01-02 10:20:30 Error: **** Due to System Out of Memory... 6 ccc 7 8 #---测试脚本--- 9 import re 10 import fileinput 11 import sys 12 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 if re.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 re 10 import fileinput 11 12 pattern = '[010|021]-d{8}' #提取区号为010或021电话号码,格式:010-12345678 13 14 for line in fileinput.input('phone.txt'): 15 if re.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'] = 'sunshine@gmail.com' 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': 'sunshine@gmail.com'} 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") >>> print m None >>> m=re.search("ab+","asdfabbbb") >>> print m <_sre.SRE_Match object at 0x011B1988> >>> print m.group() abbbb
上例不能用re.match,因为match匹配字符串的开始,我们无法验证元字符"^"是否代表字符串的开始位置。
>>> m=re.match("^ab+","asdfabbbb") >>> print m None >>> m=re.match("ab+","asdfabbbb") >>> print m 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),(?P<name>REs),这是无名称的组和有名称的group,有名称的group,可以通过matchObject.group(name).获取匹配的group,而无名称的 group可以通过从1开始的group序号来获取匹配的组,如matchObject.group(1)。
11).元字符(.)
元字符“.”在默认模式下,匹配除换行符外的所有字符。在DOTALL模式下,匹配所有字符,包括换行符。
>>> import re >>> re.match(".","\n") >>> m=re.match(".","\n") >>> print m None >>> m=re.match(".","\n",re.DOTALL) >>> print m <_sre.SRE_Match object at 0x00C2CE20> >>> m.group() '\n'
3.8.2 re模块方法
re.match
re.match 尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。
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
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式对象的一个例子:
import re 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, <em>world</em>! print re.sub(emphasis_pattern,r'<em>\1</em>','hello, *world*!')
贪婪模式和非贪婪模式
重复运算符默认是贪婪的( greedy
),它会进行尽可能多的匹配。如下面的模式使用的就是贪婪模式:
1 import re 2 3 emphasis_pattern = r'\*(.+)\*' 4 text = '*This* is *it*' 5 # <em>This* is *it<em> 6 print re.sub(emphasis_pattern,r'<em>\1<em>',text)
非贪婪模式和贪婪模式相反,它会尽可能少的匹配。将重复运算符变成非贪婪模式只需要在其后加一个问号( ?
)即可:
1 import re 2 3 emphasis_pattern = r'\*(.+?)\*' 4 text = '*This* is *it*' 5 # <em>This<em> is <em>it<em> 6 print re.sub(emphasis_pattern,r'<em>\1<em>',text)