首页 > 技术文章 > python基础教程总结9——模块,包,标准库

zxqstrong 2015-07-22 10:41 原文

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

  导入全部属性(由于容易覆盖当前名称空间中现有的名字,所以一般不推荐使用,适合模块中变量名很长并且变量很多的情况)

 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.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 尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。 

复制代码
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

  可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式对象的一个例子:

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)
复制代码

 

推荐阅读