Python([KK] 英語發音: /'paɪθɑn/, [DJ] 英語發音: /ˈpaiθən/),是一种面向对象、直譯式计算机程序设计语言,也是一种功能强大而完善的通用型语言,已经具有十多年的发展历史,成熟且稳定。
这种语言具有非常简捷而清晰的语法特点,适合完成各种高层任务,几乎可以在所有的操作系统中运行。
这种语言具有非常简捷而清晰的语法特点,适合完成各种高层任务,几乎可以在所有的操作系统中运行。
以前写过一个刷校内网的人气的工具,Java的(以后再也不行Java程序了),里面用到了验证码识别,那段代码不是我自己写的:-) 校内的验证是完全单色没有任何干挠的验证码,识别起来比较容易,不过从那段代码中可以看到基本的验证码识别方式。这几天在写一个程序的时候需要识别验证码,因为程序是Python写的自然打算用Python进行验证码的识别。
以前没用Python处理过图像,不太了解PIL(Python Image Library)的用法,这几天看了看PIL,发现它太强大了,简直和ImageMagic,PS可以相比了。(这里有PIL不错的文档)
由于上面的验证码是24位的jpeg图像,并且包含了噪点,所以我们要做的就是去噪和去色,我拿PS找了张验证码试了试,使用PS滤镜中的去噪效果还行,但是没有在PIL找到去噪的函数,后来发现中值过滤后可以去掉大部分的噪点,而且PIL里有现成的函数,接下来我试着直接把图像转换为单色,结果发现还是会有不过的噪点留了下来,因为中值过滤时把不少噪点淡化了,但转换为音色时这些噪点又被强化显示了,于是在中值过滤后对图像亮度进行加强处理,然后再转换为单色,这样验证码图片就变得比较容易识别了:
上面这些处理使用Python才几行:
PYTHON:
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.show()
接下来就是提取这些数字的字模,使用shell脚本下载100幅图片,抽出三张图片获取字模:
PYTHON:
#!/usr/bin/env python
#encoding=utf-8
import Image,ImageEnhance,ImageFilter
import sys
image_name = "./images/81.jpeg"
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
#im.show()
#all by pixel
s = 12 #start postion of first number
w = 10 #width of each number
h = 15 #end postion from top
t = 2 #start postion of top
im_new = []
#split four numbers in the picture
for i in range(4):
im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h))
im_new.append(im1)
f = file("data.txt","a")
for k in range(4):
l = []
#im_new[k].show()
for i in range(13):
for j in range(10):
if (im_new[k].getpixel((j,i)) == 255):
l.append(0)
else:
l.append(1)
f.write("l=[")
n = 0
for i in l:
if (n%10==0):
f.write("\n")
f.write(str(i)+",")
n+=1
f.write("]\n")
把字模保存为list,用于接下来的匹配;
提取完字模后剩下来的就是对需要处理的图片进行与数据库中的字模进行匹配了,基本的思路就是看相应点的重合率,但是由于噪点的影响在对(6,8)(8,3) (5,9)的匹配时容易出错,俺自己针对已有的100幅图片数据采集进行分析,采用了双向匹配(图片与字模分别作为基点),做了半天的测试终于可以实现 100%的识别率。
PYTHON:
#!/usr/bin/env python
#encoding=utf-8
import Image,ImageEnhance,ImageFilter
import Data
DEBUG = False
def d_print(*msg):
global DEBUG
if DEBUG:
for i in msg:
print i,
print
else:
pass
def Get_Num(l=[]):
min1 = []
min2 = []
for n in Data.N:
count1=count2=count3=count4=0
if (len(l) != len(n)):
print "Wrong pic"
exit()
for i in range(len(l)):
if (l[i] == 1):
count1+=1
if (n[i] == 1):
count2+=1
for i in range(len(l)):
if (n[i] == 1):
count3+=1
if (l[i] == 1):
count4+=1
d_print(count1,count2,count3,count4)
min1.append(count1-count2)
min2.append(count3-count4)
d_print(min1,"\n",min2)
for i in range(10):
if (min1[i] <= 2 or min2[i] <= 2):
if ((abs(min1[i] - min2[i])) <10):
return i
for i in range(10):
if (min1[i] <= 4 or min2[i] <= 4):
if (abs(min1[i] - min2[i]) <= 2):
return i
for i in range(10):
flag = False
if (min1[i] <= 3 or min2[i] <= 3):
for j in range(10):
if (j != i and (min1[j] <5 or min2[j] <5)):
flag = True
else:
pass
if (not flag):
return i
for i in range(10):
if (min1[i] <= 5 or min2[i] <= 5):
if (abs(min1[i] - min2[i]) <= 10):
return i
for i in range(10):
if (min1[i] <= 10 or min2[i] <= 10):
if (abs(min1[i] - min2[i]) <= 3):
return i
#end of function Get_Num
def Pic_Reg(image_name=None):
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.show()
#all by pixel
s = 12 #start postion of first number
w = 10 #width of each number
h = 15 #end postion from top
t = 2 #start postion of top
im_new = []
#split four numbers in the picture
for i in range(4):
im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h))
im_new.append(im1)
s = ""
for k in range(4):
l = []
#im_new[k].show()
for i in range(13):
for j in range(10):
if (im_new[k].getpixel((j,i)) == 255):
l.append(0)
else:
l.append(1)
s+=str(Get_Num(l))
return s
print Pic_Reg("./images/22.jpeg")
这里再提一下验证码识别的基本方法:截图,二值化、中值滤波去噪、分割、紧缩重排(让高矮统一)、字库特征匹配识别。
这里只是针对一般的验证码,高级验证码的识别这里有篇不错的文章,太复杂的话涉及的东西就多了,那俺就没兴趣了,人工智能(好恐怖),俺只喜欢简单的东西。
以前没用Python处理过图像,不太了解PIL(Python Image Library)的用法,这几天看了看PIL,发现它太强大了,简直和ImageMagic,PS可以相比了。(这里有PIL不错的文档)
由于上面的验证码是24位的jpeg图像,并且包含了噪点,所以我们要做的就是去噪和去色,我拿PS找了张验证码试了试,使用PS滤镜中的去噪效果还行,但是没有在PIL找到去噪的函数,后来发现中值过滤后可以去掉大部分的噪点,而且PIL里有现成的函数,接下来我试着直接把图像转换为单色,结果发现还是会有不过的噪点留了下来,因为中值过滤时把不少噪点淡化了,但转换为音色时这些噪点又被强化显示了,于是在中值过滤后对图像亮度进行加强处理,然后再转换为单色,这样验证码图片就变得比较容易识别了:
上面这些处理使用Python才几行:
PYTHON:
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.show()
接下来就是提取这些数字的字模,使用shell脚本下载100幅图片,抽出三张图片获取字模:
PYTHON:
#!/usr/bin/env python
#encoding=utf-8
import Image,ImageEnhance,ImageFilter
import sys
image_name = "./images/81.jpeg"
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
#im.show()
#all by pixel
s = 12 #start postion of first number
w = 10 #width of each number
h = 15 #end postion from top
t = 2 #start postion of top
im_new = []
#split four numbers in the picture
for i in range(4):
im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h))
im_new.append(im1)
f = file("data.txt","a")
for k in range(4):
l = []
#im_new[k].show()
for i in range(13):
for j in range(10):
if (im_new[k].getpixel((j,i)) == 255):
l.append(0)
else:
l.append(1)
f.write("l=[")
n = 0
for i in l:
if (n%10==0):
f.write("\n")
f.write(str(i)+",")
n+=1
f.write("]\n")
把字模保存为list,用于接下来的匹配;
提取完字模后剩下来的就是对需要处理的图片进行与数据库中的字模进行匹配了,基本的思路就是看相应点的重合率,但是由于噪点的影响在对(6,8)(8,3) (5,9)的匹配时容易出错,俺自己针对已有的100幅图片数据采集进行分析,采用了双向匹配(图片与字模分别作为基点),做了半天的测试终于可以实现 100%的识别率。
PYTHON:
#!/usr/bin/env python
#encoding=utf-8
import Image,ImageEnhance,ImageFilter
import Data
DEBUG = False
def d_print(*msg):
global DEBUG
if DEBUG:
for i in msg:
print i,
else:
pass
def Get_Num(l=[]):
min1 = []
min2 = []
for n in Data.N:
count1=count2=count3=count4=0
if (len(l) != len(n)):
print "Wrong pic"
exit()
for i in range(len(l)):
if (l[i] == 1):
count1+=1
if (n[i] == 1):
count2+=1
for i in range(len(l)):
if (n[i] == 1):
count3+=1
if (l[i] == 1):
count4+=1
d_print(count1,count2,count3,count4)
min1.append(count1-count2)
min2.append(count3-count4)
d_print(min1,"\n",min2)
for i in range(10):
if (min1[i] <= 2 or min2[i] <= 2):
if ((abs(min1[i] - min2[i])) <10):
return i
for i in range(10):
if (min1[i] <= 4 or min2[i] <= 4):
if (abs(min1[i] - min2[i]) <= 2):
return i
for i in range(10):
flag = False
if (min1[i] <= 3 or min2[i] <= 3):
for j in range(10):
if (j != i and (min1[j] <5 or min2[j] <5)):
flag = True
else:
pass
if (not flag):
return i
for i in range(10):
if (min1[i] <= 5 or min2[i] <= 5):
if (abs(min1[i] - min2[i]) <= 10):
return i
for i in range(10):
if (min1[i] <= 10 or min2[i] <= 10):
if (abs(min1[i] - min2[i]) <= 3):
return i
#end of function Get_Num
def Pic_Reg(image_name=None):
im = Image.open(image_name)
im = im.filter(ImageFilter.MedianFilter())
enhancer = ImageEnhance.Contrast(im)
im = enhancer.enhance(2)
im = im.convert('1')
im.show()
#all by pixel
s = 12 #start postion of first number
w = 10 #width of each number
h = 15 #end postion from top
t = 2 #start postion of top
im_new = []
#split four numbers in the picture
for i in range(4):
im1 = im.crop((s+w*i+i*2,t,s+w*(i+1)+i*2,h))
im_new.append(im1)
s = ""
for k in range(4):
l = []
#im_new[k].show()
for i in range(13):
for j in range(10):
if (im_new[k].getpixel((j,i)) == 255):
l.append(0)
else:
l.append(1)
s+=str(Get_Num(l))
return s
print Pic_Reg("./images/22.jpeg")
这里再提一下验证码识别的基本方法:截图,二值化、中值滤波去噪、分割、紧缩重排(让高矮统一)、字库特征匹配识别。
这里只是针对一般的验证码,高级验证码的识别这里有篇不错的文章,太复杂的话涉及的东西就多了,那俺就没兴趣了,人工智能(好恐怖),俺只喜欢简单的东西。
python如何判断一个字符串只包含数字字符
python 字符串比较
下面列出了常用的python实现的字符串操作
1.复制字符串
#strcpy(sStr1,sStr2)
sStr1 = 'strcpy'
sStr2 = sStr1
sStr1 = 'strcpy2'
print sStr2
2.连接字符串
#strcat(sStr1,sStr2)
sStr1 = 'strcat'
sStr2 = 'append'
sStr1 += sStr2
print sStr1
3.查找字符
#strchr(sStr1,sStr2)
sStr1 = 'strchr'
sStr2 = 'r'
nPos = sStr1.index(sStr2)
print nPos
4.比较字符串
#strcmp(sStr1,sStr2)
sStr1 = 'strchr'
sStr2 = 'strch'
print cmp(sStr1,sStr2)
5.扫描字符串是否包含指定的字符
#strspn(sStr1,sStr2)
sStr1 = '12345678'
sStr2 = '456'
#sStr1 and chars both in sStr1 and sStr2
print len(sStr1 and sStr2)
6.字符串长度
#strlen(sStr1)
sStr1 = 'strlen'
print len(sStr1)
7.将字符串中的小写字符转换为大写字符
#strlwr(sStr1)
sStr1 = 'JCstrlwr'
sStr1 = sStr1.upper()
print sStr1
8.追加指定长度的字符串
#strncat(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = 'abcdef'
n = 3
sStr1 += sStr2[0:n]
print sStr1
9.字符串指定长度比较
#strncmp(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = '123bc'
n = 3
print cmp(sStr1[0:n],sStr2[0:n])
10.复制指定长度的字符
#strncpy(sStr1,sStr2,n)
sStr1 = ''
sStr2 = '12345'
n = 3
sStr1 = sStr2[0:n]
print sStr1
11.字符串比较,不区分大小写
#stricmp(sStr1,sStr2)
sStr1 = 'abcefg'
sStr2 = 'ABCEFG'
print cmp(sStr1.upper(),sStr2.upper())
12.将字符串前n个字符替换为指定的字符
#strnset(sStr1,ch,n)
sStr1 = '12345'
ch = 'r'
n = 3
sStr1 = n * ch + sStr1[3:]
print sStr1
13.扫描字符串
#strpbrk(sStr1,sStr2)
sStr1 = 'cekjgdklab'
sStr2 = 'gka'
nPos = -1
for c in sStr1:
if c in sStr2:
nPos = sStr1.index(c)
break
print nPos
14.翻转字符串
#strrev(sStr1)
sStr1 = 'abcdefg'
sStr1 = sStr1[::-1]
print sStr1
15.查找字符串
python strstr
#strstr(sStr1,sStr2)
sStr1 = 'abcdefg'
sStr2 = 'cde'
print sStr1.find(sStr2)
16.分割字符串
#strtok(sStr1,sStr2)
sStr1 = 'ab,cde,fgh,ijk'
sStr2 = ','
sStr1 = sStr1[sStr1.find(sStr2) + 1:]
print sStr1
python 字符串比较
下面列出了常用的python实现的字符串操作
1.复制字符串
#strcpy(sStr1,sStr2)
sStr1 = 'strcpy'
sStr2 = sStr1
sStr1 = 'strcpy2'
print sStr2
2.连接字符串
#strcat(sStr1,sStr2)
sStr1 = 'strcat'
sStr2 = 'append'
sStr1 += sStr2
print sStr1
3.查找字符
#strchr(sStr1,sStr2)
sStr1 = 'strchr'
sStr2 = 'r'
nPos = sStr1.index(sStr2)
print nPos
4.比较字符串
#strcmp(sStr1,sStr2)
sStr1 = 'strchr'
sStr2 = 'strch'
print cmp(sStr1,sStr2)
5.扫描字符串是否包含指定的字符
#strspn(sStr1,sStr2)
sStr1 = '12345678'
sStr2 = '456'
#sStr1 and chars both in sStr1 and sStr2
print len(sStr1 and sStr2)
6.字符串长度
#strlen(sStr1)
sStr1 = 'strlen'
print len(sStr1)
7.将字符串中的小写字符转换为大写字符
#strlwr(sStr1)
sStr1 = 'JCstrlwr'
sStr1 = sStr1.upper()
print sStr1
8.追加指定长度的字符串
#strncat(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = 'abcdef'
n = 3
sStr1 += sStr2[0:n]
print sStr1
9.字符串指定长度比较
#strncmp(sStr1,sStr2,n)
sStr1 = '12345'
sStr2 = '123bc'
n = 3
print cmp(sStr1[0:n],sStr2[0:n])
10.复制指定长度的字符
#strncpy(sStr1,sStr2,n)
sStr1 = ''
sStr2 = '12345'
n = 3
sStr1 = sStr2[0:n]
print sStr1
11.字符串比较,不区分大小写
#stricmp(sStr1,sStr2)
sStr1 = 'abcefg'
sStr2 = 'ABCEFG'
print cmp(sStr1.upper(),sStr2.upper())
12.将字符串前n个字符替换为指定的字符
#strnset(sStr1,ch,n)
sStr1 = '12345'
ch = 'r'
n = 3
sStr1 = n * ch + sStr1[3:]
print sStr1
13.扫描字符串
#strpbrk(sStr1,sStr2)
sStr1 = 'cekjgdklab'
sStr2 = 'gka'
nPos = -1
for c in sStr1:
if c in sStr2:
nPos = sStr1.index(c)
break
print nPos
14.翻转字符串
#strrev(sStr1)
sStr1 = 'abcdefg'
sStr1 = sStr1[::-1]
print sStr1
15.查找字符串
python strstr
#strstr(sStr1,sStr2)
sStr1 = 'abcdefg'
sStr2 = 'cde'
print sStr1.find(sStr2)
16.分割字符串
#strtok(sStr1,sStr2)
sStr1 = 'ab,cde,fgh,ijk'
sStr2 = ','
sStr1 = sStr1[sStr1.find(sStr2) + 1:]
print sStr1
tokyo cabinet是一个很有名的缓存数据库,在网上大致的描述是这样的:tokyo cabinet 是日本人 平林幹雄 开发的一款 DBM 数据库,该数据库读写非常快,哈希模式写入100万条数据只需0.643秒,读取100万条数据只需0.773秒,是 Berkeley DB 等 DBM 的几倍。(其运行条件是:linux kernel 2.6.16, ext3的文件系统,Intel Xeon quad core 2.3GHz 8G RAM compile gcc4.2.3(-O3参数编译优化) glibc2.7),支持几乎所有的主流平台,除了windows,哈哈哈!比起windows来说可能linux,unix,mac os x会更好点。
我是今年年初的时候在杭州的时候接触这个好东东的,我们的系统也是要用它来做服务器缓存的,当时是用的c来做的,回到北京以后,参加了一次python的会课,那次会课恰恰清风提到了tokyo cabinet在python中的应用,不过他好像当时并没有现成的python封装库,自己完成的一些封装,tokyo cabinet已经有c,perl,ruby,java,lua的官方版本,可是就是唯有python没有,据说这个作者不会python有关系,由于现在我做的东西急需一个cache数据库,所有又打起了它的主意,昨天在晚上google了下,得来全不费功夫.
这是一个现成的tokyo cabinet的python封装库http://github.com/rsms/tc,不过先得编译安装tokyo cabinet的c库,安装过程如下:
wget http://1978th.net/tokyocabinet/tokyocabinet-1.4.43.tar.gz
tar zxvf tokyocabinet-1.4.43.tar.gz
cd tokyocabinet-1.4.43/
./configure
make
make install
然后再安装python的egg包,因为该项目是用git来管理的,所以先得安装git
git clone git://github.com/rsms/tc.git
cd tc
sudo python setup.py install
不过这里要注意有可能会出现有可能在安装的过程中会出现libtokyocabinet.so.8: cannot open shared object file: No such file or directory,请检查你的/etc/ld.so.conf文件,看它有没有包含你的tokyo cabinet的库路径,一般来讲tokyo cabinet会安装在/usr/local/lib下面,可以把这个路径写入/etc/ld.so.conf中,然后再ldconfig /etc/ld.so.conf就可以顺利安装了tc了
至于怎么去用,你可以参考下tc下的/lib/tc/test/的三个hdb.py,bdb.py,fdb.py的单元测试的例子,例子很详细
我是今年年初的时候在杭州的时候接触这个好东东的,我们的系统也是要用它来做服务器缓存的,当时是用的c来做的,回到北京以后,参加了一次python的会课,那次会课恰恰清风提到了tokyo cabinet在python中的应用,不过他好像当时并没有现成的python封装库,自己完成的一些封装,tokyo cabinet已经有c,perl,ruby,java,lua的官方版本,可是就是唯有python没有,据说这个作者不会python有关系,由于现在我做的东西急需一个cache数据库,所有又打起了它的主意,昨天在晚上google了下,得来全不费功夫.
这是一个现成的tokyo cabinet的python封装库http://github.com/rsms/tc,不过先得编译安装tokyo cabinet的c库,安装过程如下:
wget http://1978th.net/tokyocabinet/tokyocabinet-1.4.43.tar.gz
tar zxvf tokyocabinet-1.4.43.tar.gz
cd tokyocabinet-1.4.43/
./configure
make
make install
然后再安装python的egg包,因为该项目是用git来管理的,所以先得安装git
git clone git://github.com/rsms/tc.git
cd tc
sudo python setup.py install
不过这里要注意有可能会出现有可能在安装的过程中会出现libtokyocabinet.so.8: cannot open shared object file: No such file or directory,请检查你的/etc/ld.so.conf文件,看它有没有包含你的tokyo cabinet的库路径,一般来讲tokyo cabinet会安装在/usr/local/lib下面,可以把这个路径写入/etc/ld.so.conf中,然后再ldconfig /etc/ld.so.conf就可以顺利安装了tc了
至于怎么去用,你可以参考下tc下的/lib/tc/test/的三个hdb.py,bdb.py,fdb.py的单元测试的例子,例子很详细
注:压力测试要区分基准测试,应用测试, 不同的应用有不同的表现, 基准测试主要测试服务器的性能,而不是服务器在某个应用下的表现.进入正题.
Siege(英文意思是围攻)是一个压力测试和评测工具
#./configure --prefix=/usr/local/siege ;
#make
#make install
任务列表:url.txt文件
siege -c 20 -r 2 -f url.txt
参数说明:
-c 20 并发20个用户
-r 2 重复循环2次
-f url.txt任务列表:URL列表
输出样例:
** Siege 2.59
** Preparing 20 concurrent users for battle. 这次“战斗”准备了20个并发用户
The server is now under siege.. done. 服务在“围攻”测试中:
Transactions: 40 hits 完成40次处理
Availability: 100.00 % 成功率
Elapsed time: 7.67 secs 总共用时
Data transferred: 877340 bytes 共数据传输:877340字节
Response time: 1.65 secs 相应用时1.65秒:显示网络连接的速度
Transaction rate: 5.22 trans/sec 平均每秒完成5.22次处理:表示服务器后台处理的速度
Throughput: 114385.92 bytes/sec 平均每秒传送数据:114385.92字节
Concurrency: 8.59 最高并发数 8.59
Successful transactions: 40 成功处理次数
Failed transactions: 0 失败处理次数
注意:由于速度很快,可能会达不到并发速度很高就已经完成。Response time显示的是测试机器和被测试服务器之间网络链接状况。Transaction rate则表示服务器端任务处理的完成速度。
辅助工具:
增量压力测试:
为了方便增量压力测试,siege还包含了一些辅助工具:
bombardment (1)
是一个辅助工具:用于按照增量用户压力测试:
使用样例:
bombardment url.txt 5 3 4 1
初始化URL列表:url.txt
初始化为:5个用户
每次增加:3个用户
运行:4次
每个客户端之间的延迟为:1秒
输出成CSV格式:
siege2csv.pl (1)
siege2csv.pl将bombardment的输出变成CSV格式:
Time Data Transferred Response Time Transaction Rate Throughput Concurrency Code 200 (note that this is horribly broken.)
242 60.22 603064 0.02 4.02 10014.35 0.08
605 59.98 1507660 0.01 10.09 25136.05 0.12
938 59.98 2337496 0.02 15.64 38971.26 0.26
1157 60 2883244 0.04 19.28 48054.07 0.78
webbench
-----------------------------------------
webbench最多可以模拟3万个并发连接去测试网站的负载能力
tar zxvf webbench-1.5.tar.gz
cd webbench-1.5
make && make install
webbench -c 500 -t 30 http://127.0.0.1/test.jpg
参数说明:-c表示并发数,-t表示时间(秒)
测试结果示例:
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://127.0.0.1/test.jpg
500 clients, running 30 sec.
Speed=3230 pages/min, 11614212 bytes/sec.
Requests: 1615 susceed, 0 failed.
参数说明:
-c 20 并发20个用户
-r 2 重复循环2次
-f www.chedong.com.url 任务列表:URL列表
输出样例:
** Siege 2.59
** Preparing 20 concurrent users for battle. 这次“战斗”准备了20个并发用户
The server is now under siege.. done. 服务在“围攻”测试中:
Transactions: 40 hits 完成40次处理
Availability: 100.00 % 成功率
Elapsed time: 7.67 secs 总共用时
Data transferred: 877340 bytes 共数据传输:877340字节
Response time: 1.65 secs 相应用时1.65秒:显示网络连接的速度
Transaction rate: 5.22 trans/sec 平均每秒完成5.22次处理:表示服务器后台处理的速度
Throughput: 114385.92 bytes/sec 平均每秒传送数据:114385.92字节
Concurrency: 8.59 最高并发数 8.59
Successful transactions: 40 成功处理次数
Failed transactions: 0 失败处理次数
注意:由于速度很快,可能会达不到并发速度很高就已经完成。Response time显示的是测试机器和被测试服务器之间网络链接状况。Transaction rate则表示服务器端任务处理的完成速度。
辅助工具:
增量压力测试:
为了方便增量压力测试,siege还包含了一些辅助工具:
bombardment (1)
是一个辅助工具:用于按照增量用户压力测试:
使用样例:
bombardment urlfile.txt 5 3 4 1
初始化URL列表:urlfile.txt
初始化为:5个用户
每次增加:3个用户
运行:4次
每个客户端之间的延迟为:1秒
输出成CSV格式:
siege2csv.pl (1)
siege2csv.pl将bombardment的输出变成CSV格式:
Time Data Transferred Response Time Transaction Rate Throughput Concurrency Code 200 (note that this is horribly broken.)
242 60.22 603064 0.02 4.02 10014.35 0.08
605 59.98 1507660 0.01 10.09 25136.05 0.12
938 59.98 2337496 0.02 15.64 38971.26 0.26
1157 60 2883244 0.04 19.28 48054.07 0.78
APACHE 的 AB
-----------------------------------------
./ab -c 300 -n 1000 http://www.zaojiao.com/test.html
ab -n 全部请求数 -c 并发数 测试url
Concurrency Level: 50 #并发数
Time taken for tests: 92.76140 seconds #全部请求完成耗时
Complete requests: 10000 #全部请求数
Failed requests: 1974 #失败的请求
(Connect: 0, Length: 1974, Exceptions: 0)
Write errors: 0
Total transferred: 827019400 bytes #总传输大小
HTML transferred: 825219400 bytes
Requests per second: 108.61 [#/sec] (mean) #每秒请求数(平均)
Time per request: 460.381 [ms] (mean) #每次并发请求时间(所有并发)
Time per request: 9.208 [ms] (mean, across all concurrent requests) #每一请求时间(并发平均)
Transfer rate: 8771.39 [Kbytes/sec] received #传输速率
以下结果时间每次有所偏差,均取相对平均值。
test.html
1 1000 1.296 771/s
5 1000 0.4826 2072/s
10 1000 5.142 194/s
700 700 3.36 208/s
700 2100 6514 321/s
2000 2000 3.2 608
6000 6000 6.2 983
这三种工具从机理上是一样的,根据测试的要求选择合适的工具.
Siege(英文意思是围攻)是一个压力测试和评测工具
#./configure --prefix=/usr/local/siege ;
#make
#make install
任务列表:url.txt文件
siege -c 20 -r 2 -f url.txt
参数说明:
-c 20 并发20个用户
-r 2 重复循环2次
-f url.txt任务列表:URL列表
输出样例:
** Siege 2.59
** Preparing 20 concurrent users for battle. 这次“战斗”准备了20个并发用户
The server is now under siege.. done. 服务在“围攻”测试中:
Transactions: 40 hits 完成40次处理
Availability: 100.00 % 成功率
Elapsed time: 7.67 secs 总共用时
Data transferred: 877340 bytes 共数据传输:877340字节
Response time: 1.65 secs 相应用时1.65秒:显示网络连接的速度
Transaction rate: 5.22 trans/sec 平均每秒完成5.22次处理:表示服务器后台处理的速度
Throughput: 114385.92 bytes/sec 平均每秒传送数据:114385.92字节
Concurrency: 8.59 最高并发数 8.59
Successful transactions: 40 成功处理次数
Failed transactions: 0 失败处理次数
注意:由于速度很快,可能会达不到并发速度很高就已经完成。Response time显示的是测试机器和被测试服务器之间网络链接状况。Transaction rate则表示服务器端任务处理的完成速度。
辅助工具:
增量压力测试:
为了方便增量压力测试,siege还包含了一些辅助工具:
bombardment (1)
是一个辅助工具:用于按照增量用户压力测试:
使用样例:
bombardment url.txt 5 3 4 1
初始化URL列表:url.txt
初始化为:5个用户
每次增加:3个用户
运行:4次
每个客户端之间的延迟为:1秒
输出成CSV格式:
siege2csv.pl (1)
siege2csv.pl将bombardment的输出变成CSV格式:
Time Data Transferred Response Time Transaction Rate Throughput Concurrency Code 200 (note that this is horribly broken.)
242 60.22 603064 0.02 4.02 10014.35 0.08
605 59.98 1507660 0.01 10.09 25136.05 0.12
938 59.98 2337496 0.02 15.64 38971.26 0.26
1157 60 2883244 0.04 19.28 48054.07 0.78
webbench
-----------------------------------------
webbench最多可以模拟3万个并发连接去测试网站的负载能力
tar zxvf webbench-1.5.tar.gz
cd webbench-1.5
make && make install
webbench -c 500 -t 30 http://127.0.0.1/test.jpg
参数说明:-c表示并发数,-t表示时间(秒)
测试结果示例:
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://127.0.0.1/test.jpg
500 clients, running 30 sec.
Speed=3230 pages/min, 11614212 bytes/sec.
Requests: 1615 susceed, 0 failed.
参数说明:
-c 20 并发20个用户
-r 2 重复循环2次
-f www.chedong.com.url 任务列表:URL列表
输出样例:
** Siege 2.59
** Preparing 20 concurrent users for battle. 这次“战斗”准备了20个并发用户
The server is now under siege.. done. 服务在“围攻”测试中:
Transactions: 40 hits 完成40次处理
Availability: 100.00 % 成功率
Elapsed time: 7.67 secs 总共用时
Data transferred: 877340 bytes 共数据传输:877340字节
Response time: 1.65 secs 相应用时1.65秒:显示网络连接的速度
Transaction rate: 5.22 trans/sec 平均每秒完成5.22次处理:表示服务器后台处理的速度
Throughput: 114385.92 bytes/sec 平均每秒传送数据:114385.92字节
Concurrency: 8.59 最高并发数 8.59
Successful transactions: 40 成功处理次数
Failed transactions: 0 失败处理次数
注意:由于速度很快,可能会达不到并发速度很高就已经完成。Response time显示的是测试机器和被测试服务器之间网络链接状况。Transaction rate则表示服务器端任务处理的完成速度。
辅助工具:
增量压力测试:
为了方便增量压力测试,siege还包含了一些辅助工具:
bombardment (1)
是一个辅助工具:用于按照增量用户压力测试:
使用样例:
bombardment urlfile.txt 5 3 4 1
初始化URL列表:urlfile.txt
初始化为:5个用户
每次增加:3个用户
运行:4次
每个客户端之间的延迟为:1秒
输出成CSV格式:
siege2csv.pl (1)
siege2csv.pl将bombardment的输出变成CSV格式:
Time Data Transferred Response Time Transaction Rate Throughput Concurrency Code 200 (note that this is horribly broken.)
242 60.22 603064 0.02 4.02 10014.35 0.08
605 59.98 1507660 0.01 10.09 25136.05 0.12
938 59.98 2337496 0.02 15.64 38971.26 0.26
1157 60 2883244 0.04 19.28 48054.07 0.78
APACHE 的 AB
-----------------------------------------
./ab -c 300 -n 1000 http://www.zaojiao.com/test.html
ab -n 全部请求数 -c 并发数 测试url
Concurrency Level: 50 #并发数
Time taken for tests: 92.76140 seconds #全部请求完成耗时
Complete requests: 10000 #全部请求数
Failed requests: 1974 #失败的请求
(Connect: 0, Length: 1974, Exceptions: 0)
Write errors: 0
Total transferred: 827019400 bytes #总传输大小
HTML transferred: 825219400 bytes
Requests per second: 108.61 [#/sec] (mean) #每秒请求数(平均)
Time per request: 460.381 [ms] (mean) #每次并发请求时间(所有并发)
Time per request: 9.208 [ms] (mean, across all concurrent requests) #每一请求时间(并发平均)
Transfer rate: 8771.39 [Kbytes/sec] received #传输速率
以下结果时间每次有所偏差,均取相对平均值。
test.html
1 1000 1.296 771/s
5 1000 0.4826 2072/s
10 1000 5.142 194/s
700 700 3.36 208/s
700 2100 6514 321/s
2000 2000 3.2 608
6000 6000 6.2 983
这三种工具从机理上是一样的,根据测试的要求选择合适的工具.
字符串中字符大小写的变换:
* S.lower() #小写
* S.upper() #大写
* S.swapcase() #大小写互换
* S.capitalize() #首字母大写
* String.capwords(S) #这是模块中的方法。它把S用split()函数分开,然后用capitalize()把首字母变成大写,最后用join()合并到一起
* S.title() #只有首字母大写,其余为小写,模块中没有这个方法
字符串在输出时的对齐:
* S.ljust(width,[fillchar]) #输出width个字符,S左对齐,不足部分用fillchar填充,默认的为空格。
* S.rjust(width,[fillchar]) #右对齐
* S.center(width, [fillchar]) #中间对齐
* S.zfill(width) #把S变成width长,并在右对齐,不足部分用0补足
字符串中的搜索和替换:
* S.find(substr, [start, [end]])
#返回S中出现substr的第一个字母的标号,如果S中没有substr则返回-1。start和end作用就相当于在S[start:end]中搜索
* S.index(substr, [start, [end]])
#与find()相同,只是在S中没有substr时,会返回一个运行时错误
* S.rfind(substr, [start, [end]])
#返回S中最后出现的substr的第一个字母的标号,如果S中没有substr则返回-1,也就是说从右边算起的第一次出现的substr的首字母标号
* S.rindex(substr, [start, [end]])
* S.count(substr, [start, [end]]) #计算substr在S中出现的次数
* S.replace(oldstr, newstr, [count])
#把S中的oldstar替换为newstr,count为替换次数。这是替换的通用形式,还有一些函数进行特殊字符的替换
* S.strip([chars])
#把S中前后chars中有的字符全部去掉,可以理解为把S前后chars替换为None
* S.lstrip([chars])
* S.rstrip([chars]) 进行去除[chars]字符 如:s.rstrip('\n') 去掉换行符.
* S.expandtabs([tabsize])
#把S中的tab字符替换没空格,每个tab替换为tabsize个空格,默认是8个
字符串的分割和组合:
* S.split([sep, [maxsplit]])
#以sep为分隔符,把S分成一个list。maxsplit表示分割的次数。默认的分割符为空白字符
* S.rsplit([sep, [maxsplit]])
* S.splitlines([keepends])
#把S按照行分割符分为一个list,keepends是一个bool值,如果为真每行后而会保留行分割符。
* S.join(seq) #把seq代表的序列──字符串序列,用S连接起来
字符串的mapping,这一功能包含两个函数:
* String.maketrans(from, to)
#返回一个256个字符组成的翻译表,其中from中的字符被一一对应地转换成to,所以from和to必须是等长的。
* S.translate(table[,deletechars])
#使用上面的函数产后的翻译表,把S进行翻译,并把deletechars中有的字符删掉。需要注意的是,如果S为unicode字符串,那么就不支持 deletechars参数,可以使用把某个字符翻译为None的方式实现相同的功能。此外还可以使用codecs模块的功能来创建更加功能强大的翻译 表。
字符串还有一对编码和解码的函数:
* S.encode([encoding,[errors]])
#其中encoding可以有多种值,比如gb2312 gbk gb18030 bz2 zlib big5 bzse64等都支持。errors默认值为"strict",意思是UnicodeError。可能的值还有'ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace' 和所有的通过codecs.register_error注册的值。这一部分内容涉及codecs模块,不是特明白
* S.decode([encoding,[errors]])
字符串的测试函数,这一类函数在string模块中没有,这些函数返回的都是bool值:
* S.startwith(prefix[,start[,end]]) #是否以prefix开头
* S.endwith(suffix[,start[,end]]) #以suffix结尾
* S.isalnum() #是否全是字母和数字,并至少有一个字符
* S.isalpha() #是否全是字母,并至少有一个字符
* S.isdigit() #是否全是数字,并至少有一个字符
* S.isspace() #是否全是空白字符,并至少有一个字符
* S.islower() #S中的字母是否全是小写
* S.isupper() #S中的字母是否便是大写
* S.istitle() #S是否是首字母大写的
字符串类型转换函数,这几个函数只在string模块中有:
* string.atoi(s[,base])
#base默认为10,如果为0,那么s就可以是012或0x23这种形式的字符串,如果是16那么s就只能是0x23或0X12这种形式的字符串
* string.atol(s[,base]) #转成long
* string.atof(s[,base]) #转成float
* S.lower() #小写
* S.upper() #大写
* S.swapcase() #大小写互换
* S.capitalize() #首字母大写
* String.capwords(S) #这是模块中的方法。它把S用split()函数分开,然后用capitalize()把首字母变成大写,最后用join()合并到一起
* S.title() #只有首字母大写,其余为小写,模块中没有这个方法
字符串在输出时的对齐:
* S.ljust(width,[fillchar]) #输出width个字符,S左对齐,不足部分用fillchar填充,默认的为空格。
* S.rjust(width,[fillchar]) #右对齐
* S.center(width, [fillchar]) #中间对齐
* S.zfill(width) #把S变成width长,并在右对齐,不足部分用0补足
字符串中的搜索和替换:
* S.find(substr, [start, [end]])
#返回S中出现substr的第一个字母的标号,如果S中没有substr则返回-1。start和end作用就相当于在S[start:end]中搜索
* S.index(substr, [start, [end]])
#与find()相同,只是在S中没有substr时,会返回一个运行时错误
* S.rfind(substr, [start, [end]])
#返回S中最后出现的substr的第一个字母的标号,如果S中没有substr则返回-1,也就是说从右边算起的第一次出现的substr的首字母标号
* S.rindex(substr, [start, [end]])
* S.count(substr, [start, [end]]) #计算substr在S中出现的次数
* S.replace(oldstr, newstr, [count])
#把S中的oldstar替换为newstr,count为替换次数。这是替换的通用形式,还有一些函数进行特殊字符的替换
* S.strip([chars])
#把S中前后chars中有的字符全部去掉,可以理解为把S前后chars替换为None
* S.lstrip([chars])
* S.rstrip([chars]) 进行去除[chars]字符 如:s.rstrip('\n') 去掉换行符.
* S.expandtabs([tabsize])
#把S中的tab字符替换没空格,每个tab替换为tabsize个空格,默认是8个
字符串的分割和组合:
* S.split([sep, [maxsplit]])
#以sep为分隔符,把S分成一个list。maxsplit表示分割的次数。默认的分割符为空白字符
* S.rsplit([sep, [maxsplit]])
* S.splitlines([keepends])
#把S按照行分割符分为一个list,keepends是一个bool值,如果为真每行后而会保留行分割符。
* S.join(seq) #把seq代表的序列──字符串序列,用S连接起来
字符串的mapping,这一功能包含两个函数:
* String.maketrans(from, to)
#返回一个256个字符组成的翻译表,其中from中的字符被一一对应地转换成to,所以from和to必须是等长的。
* S.translate(table[,deletechars])
#使用上面的函数产后的翻译表,把S进行翻译,并把deletechars中有的字符删掉。需要注意的是,如果S为unicode字符串,那么就不支持 deletechars参数,可以使用把某个字符翻译为None的方式实现相同的功能。此外还可以使用codecs模块的功能来创建更加功能强大的翻译 表。
字符串还有一对编码和解码的函数:
* S.encode([encoding,[errors]])
#其中encoding可以有多种值,比如gb2312 gbk gb18030 bz2 zlib big5 bzse64等都支持。errors默认值为"strict",意思是UnicodeError。可能的值还有'ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace' 和所有的通过codecs.register_error注册的值。这一部分内容涉及codecs模块,不是特明白
* S.decode([encoding,[errors]])
字符串的测试函数,这一类函数在string模块中没有,这些函数返回的都是bool值:
* S.startwith(prefix[,start[,end]]) #是否以prefix开头
* S.endwith(suffix[,start[,end]]) #以suffix结尾
* S.isalnum() #是否全是字母和数字,并至少有一个字符
* S.isalpha() #是否全是字母,并至少有一个字符
* S.isdigit() #是否全是数字,并至少有一个字符
* S.isspace() #是否全是空白字符,并至少有一个字符
* S.islower() #S中的字母是否全是小写
* S.isupper() #S中的字母是否便是大写
* S.istitle() #S是否是首字母大写的
字符串类型转换函数,这几个函数只在string模块中有:
* string.atoi(s[,base])
#base默认为10,如果为0,那么s就可以是012或0x23这种形式的字符串,如果是16那么s就只能是0x23或0X12这种形式的字符串
* string.atol(s[,base]) #转成long
* string.atof(s[,base]) #转成float
List 的定义
li = ["a", "b", "mpilgrim", "z", "example"]
List元素定位使用
----------------------
>>> li[0]
'a'
>>> li[4]
'example'
>>> li[-1]
'example'
>>> li[-3]
'mpilgrim'
>>> li[1:3]
['b', 'mpilgrim']
>>> li[1:-1]
>>> li[:3]
['a', 'b', 'mpilgrim']
>>> li[3:]
['z', 'example']
>>> li[:]
['a', 'b', 'mpilgrim', 'z', 'example']
向 list 中增加元素
------------------------
>>> li.append("new")
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new")
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"])
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
append 向 list 的末尾追加单个元素。
insert 将单个元素插入到 list 中。数值参数是插入点的索引。请注意,list 中的元素不必唯一,现在有两个独立的元素具有
'new' 这个值,li[2] 和 li[6]。
extend 用来连接 list。请注意不要使用多个参数来调用 extend,要使用一个 list 参数进行调用。在本例中,这个 list 有
两个元素。
extend (扩展) 与 append (追加) 的差别
---------------------------
>>> li = ['a', 'b', 'c']
>>> li.extend(['d', 'e', 'f'])
>>> li
['a', 'b', 'c', 'd', 'e', 'f']
>>> len(li)
6
>>> li[-1]
'f'
>>> li = ['a', 'b', 'c']
>>> li.append(['d', 'e', 'f'])
>>> li
['a', 'b', 'c', ['d', 'e', 'f']]
>>> len(li)
4
从 list 中删除元素
------------------------
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z")
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new")
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
remove 从 list 中删除一个值的首次出现。
在 list 中搜索
--------------
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example")
5
>>> li.index("new")
2
使用 list 的运算符
---------------------------
>>> li = ['a', 'b', 'mpilgrim']
>>> li = li + ['example', 'new']
>>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two']
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3
>>> li
[1, 2, 1, 2, 1, 2]
Lists 也可以用 + 运算符连接起来。list = list + otherlist 相当于 list.extend(otherlist)。但 + 运算符把一个新 (连
接后) 的 list 作为值返回,而 extend 只修改存在的 list。也就是说,对于大型 list 来说,extend 的执行速度要快一些。
Python 支持 += 运算符。li += ['two'] 等同于 li.extend(['two'])。+= 运算符可用于 list、字符串和整数,并且它也可以
被重载用于用户自定义的类中
* 运算符可以作为一个重复器作用于 list。li = [1, 2] * 3 等同于 li = [1, 2] + [1, 2] + [1, 2],即将三个 list 连接
成一个
li = ["a", "b", "mpilgrim", "z", "example"]
List元素定位使用
----------------------
>>> li[0]
'a'
>>> li[4]
'example'
>>> li[-1]
'example'
>>> li[-3]
'mpilgrim'
>>> li[1:3]
['b', 'mpilgrim']
>>> li[1:-1]
>>> li[:3]
['a', 'b', 'mpilgrim']
>>> li[3:]
['z', 'example']
>>> li[:]
['a', 'b', 'mpilgrim', 'z', 'example']
向 list 中增加元素
------------------------
>>> li.append("new")
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new")
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"])
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
append 向 list 的末尾追加单个元素。
insert 将单个元素插入到 list 中。数值参数是插入点的索引。请注意,list 中的元素不必唯一,现在有两个独立的元素具有
'new' 这个值,li[2] 和 li[6]。
extend 用来连接 list。请注意不要使用多个参数来调用 extend,要使用一个 list 参数进行调用。在本例中,这个 list 有
两个元素。
extend (扩展) 与 append (追加) 的差别
---------------------------
>>> li = ['a', 'b', 'c']
>>> li.extend(['d', 'e', 'f'])
>>> li
['a', 'b', 'c', 'd', 'e', 'f']
>>> len(li)
6
>>> li[-1]
'f'
>>> li = ['a', 'b', 'c']
>>> li.append(['d', 'e', 'f'])
>>> li
['a', 'b', 'c', ['d', 'e', 'f']]
>>> len(li)
4
从 list 中删除元素
------------------------
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z")
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new")
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
remove 从 list 中删除一个值的首次出现。
在 list 中搜索
--------------
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example")
5
>>> li.index("new")
2
使用 list 的运算符
---------------------------
>>> li = ['a', 'b', 'mpilgrim']
>>> li = li + ['example', 'new']
>>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two']
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3
>>> li
[1, 2, 1, 2, 1, 2]
Lists 也可以用 + 运算符连接起来。list = list + otherlist 相当于 list.extend(otherlist)。但 + 运算符把一个新 (连
接后) 的 list 作为值返回,而 extend 只修改存在的 list。也就是说,对于大型 list 来说,extend 的执行速度要快一些。
Python 支持 += 运算符。li += ['two'] 等同于 li.extend(['two'])。+= 运算符可用于 list、字符串和整数,并且它也可以
被重载用于用户自定义的类中
* 运算符可以作为一个重复器作用于 list。li = [1, 2] * 3 等同于 li = [1, 2] + [1, 2] + [1, 2],即将三个 list 连接
成一个
1.打开文件代码如下:
>>> f = open(”d:test.txt”, “w”)
说明:第一个参数是文件名称,包括路径;第二个参数是打开的模式mode’r':只读(缺省。如果文件不存在,则抛出错误)’w':只写(如果文件 不存在,则自动创建文件)’a':附加到文件末尾’r+’:读写如果需要以二进制方式打开文件,需要在mode后面加上字符”b”,比如”rb”"wb” 等
2.读取内容f.read(size)参数size表示读取的数量,可以省略。如果省略size参数,则表示读取文件所有内容。 f.readline()读取文件一行的内容f.readlines()读取所有的行到数组里面[line1,line2,...lineN]。在避免将 所有文件内容加载到内存中,这种方法常常使用,便于提高效率。
3.写入文件f.write(string) 将一个字符串写入文件,如果写入结束,必须在字符串后面加上”n”,然后f.close()关闭文件
4.文件中的内容定位f.read()读取之后,文件指针到达文件的末尾,如果再来一次f.read()将会发现读取的是空内容,如果想再次读取全部内容,必须将定位指针移动到文件开始:
f.seek(0)这个函数的格式如下(单位是bytes):f.seek(offset, from_what)from_what表示开始读取的位置,offset表示从from_what再移动一定量的距离,比如f.seek(10, 3)表示定位到第三个字符并再后移10个字符。from_what值为0时表示文件的开始,它也可以省略,缺省是0即文件开头。下面给出一个完整的例 子:>>> f = open(’/tmp/workfile’, ‘r+’)
>>> f.write(’0123456789abcdef’)
>>> f.seek(5) # Go to the 6th byte in the file
>>> f.read(1)
‘5′
>>> f.seek (-3, 2) # Go to the 3rd byte before the end
>>> f.read(1)
‘d’
5.关闭文件释放资源文件操作完毕,一定要记得关闭文件f.close(),可以释放资源供其他程序使用
#打开文件和进行写操作
--------------------------------
f=open(’test.txt’,'w’)
f.write(’hello’)
f.writelines(['hi','haha'])#多行输入
f.close()
#append data
f=open(’test.txt’,'a’)
f.write(’hello’)
f.writelines(['hi','haha'])
f.close()
#连续写入后会自动关闭
open(’test.txt’,'a’).write(’11111rn’)
#把result里的元素依次填到open函数里去
result={’hello’,'u’}
exec open(’test.txt’) in result
#
selected = [] # temp list to hold matches
fp = open(’test.txt’)
for line in fp.readlines(): # Py2.2 -> “for line in fp:”
selected.append(line)
del line # Cleanup transient variable
#
open(’test.txt’).readlines()
file在python是一个特殊的类型,它用于在python程序中对外部的文件进行操作。在python中一切都是对象,file也不例外,file有file的方法和属性。下面先来看如何创建一个file对象:
* file(name[, mode[, buffering]])
file()函数用于创建一个file对象,它有一个别名叫open(),可能更形象一些,它们是内置函数。来看看它的参数。它参数都是以字符串的形式传递的。
name是文件的名字。
mode 是打开的模式,可选的值为r w a U,分别代表读(默认) 写 添加支持各种换行符的模式。用w或a模式打开文件的话,如果文件不存在,那么就自动创建。此外,用w模式打开一个已经存在的文件时,原有文件的内容会被清 空,因为一开始文件的操作的标记是在文件的开头的,这时候进行写操作,无疑会把原有的内容给抹掉。由于历史的原因,换行符在不同的系统中有不同模式,比如 在 unix中是一个n,而在windows中是’rn’,用U模式打开文件,就是支持所有的换行模式,也就说’r’ ‘n’ ‘rn’都可表示换行,会有一个tuple用来存贮这个文件中用到过的换行符。不过,虽说换行有多种模式,读到python中统一用n代替。在模式 字符的后面,还可以加上+ b t这两种标识,分别表示可以对文件同时进行读写操作和用二进制模式、文本模式(默认)打开文件。
buffering如果为0表示不进行缓冲;如果为1表示进行”行缓冲”;如果是一个大于1的数表示缓冲区的大小,应该是以字节为单位的。
file对象有自己的属性和方法。先来看看file的属性。
--------------------------------------
closed #标记文件是否已经关闭,由close()改写
encoding #文件编码
mode #打开模式
name #文件名
newlines #文件中用到的换行模式,是一个tuple
softspace #boolean型,一般为0,据说用于print
file的读写方法:
* F.read([size]) #size为读取的长度,以byte为单位
* F.readline([size])
#读一行,如果定义了size,有可能返回的只是一行的一部分
* F.readlines([size])
#把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。
* F.write(str)
#把str写到文件中,write()并不会在str后加上一个换行符
* F.writelines(seq)
#把seq的内容全部写到文件中。这个函数也只是忠实地写入,不会在每行后面加上任何东西。
file的其他方法:
* F.close()
#关闭文件。python会在一个文件不用后自动关闭文件,不过这一功能没有保证,最好还是养成自己关闭的习惯。如果一个文件在关闭后还对其进行操作会产生ValueError
* F.flush()
#把缓冲区的内容写入硬盘
* F.fileno()
#返回一个长整型的”文件标签”
* F.isatty()
#文件是否是一个终端设备文件(unix系统中的)
* F.tell()
#返回文件操作标记的当前位置,以文件的开头为原点
* F.next()
#返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。
* F.seek(offset[,whence])
# 将文件打操作标记移到offset的位置。这个offset一般是相对于文件的开头来计算的,一般为正数。但如果提供了whence参数就不一定了, whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。需要注意,如果文件以a或a+的模式打开,每次进 行写操作时,文件操作标记会自动返回到文件末尾。
* F.truncate([size])
#把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。如果size比文件的大小还要大,依据系统的不同可能是不改变文件,也可能是用0把文件补到相应的大小,也可能是以一些随机的内容加上去。
>>> f = open(”d:test.txt”, “w”)
说明:第一个参数是文件名称,包括路径;第二个参数是打开的模式mode’r':只读(缺省。如果文件不存在,则抛出错误)’w':只写(如果文件 不存在,则自动创建文件)’a':附加到文件末尾’r+’:读写如果需要以二进制方式打开文件,需要在mode后面加上字符”b”,比如”rb”"wb” 等
2.读取内容f.read(size)参数size表示读取的数量,可以省略。如果省略size参数,则表示读取文件所有内容。 f.readline()读取文件一行的内容f.readlines()读取所有的行到数组里面[line1,line2,...lineN]。在避免将 所有文件内容加载到内存中,这种方法常常使用,便于提高效率。
3.写入文件f.write(string) 将一个字符串写入文件,如果写入结束,必须在字符串后面加上”n”,然后f.close()关闭文件
4.文件中的内容定位f.read()读取之后,文件指针到达文件的末尾,如果再来一次f.read()将会发现读取的是空内容,如果想再次读取全部内容,必须将定位指针移动到文件开始:
f.seek(0)这个函数的格式如下(单位是bytes):f.seek(offset, from_what)from_what表示开始读取的位置,offset表示从from_what再移动一定量的距离,比如f.seek(10, 3)表示定位到第三个字符并再后移10个字符。from_what值为0时表示文件的开始,它也可以省略,缺省是0即文件开头。下面给出一个完整的例 子:>>> f = open(’/tmp/workfile’, ‘r+’)
>>> f.write(’0123456789abcdef’)
>>> f.seek(5) # Go to the 6th byte in the file
>>> f.read(1)
‘5′
>>> f.seek (-3, 2) # Go to the 3rd byte before the end
>>> f.read(1)
‘d’
5.关闭文件释放资源文件操作完毕,一定要记得关闭文件f.close(),可以释放资源供其他程序使用
#打开文件和进行写操作
--------------------------------
f=open(’test.txt’,'w’)
f.write(’hello’)
f.writelines(['hi','haha'])#多行输入
f.close()
#append data
f=open(’test.txt’,'a’)
f.write(’hello’)
f.writelines(['hi','haha'])
f.close()
#连续写入后会自动关闭
open(’test.txt’,'a’).write(’11111rn’)
#把result里的元素依次填到open函数里去
result={’hello’,'u’}
exec open(’test.txt’) in result
#
selected = [] # temp list to hold matches
fp = open(’test.txt’)
for line in fp.readlines(): # Py2.2 -> “for line in fp:”
selected.append(line)
del line # Cleanup transient variable
#
open(’test.txt’).readlines()
file在python是一个特殊的类型,它用于在python程序中对外部的文件进行操作。在python中一切都是对象,file也不例外,file有file的方法和属性。下面先来看如何创建一个file对象:
* file(name[, mode[, buffering]])
file()函数用于创建一个file对象,它有一个别名叫open(),可能更形象一些,它们是内置函数。来看看它的参数。它参数都是以字符串的形式传递的。
name是文件的名字。
mode 是打开的模式,可选的值为r w a U,分别代表读(默认) 写 添加支持各种换行符的模式。用w或a模式打开文件的话,如果文件不存在,那么就自动创建。此外,用w模式打开一个已经存在的文件时,原有文件的内容会被清 空,因为一开始文件的操作的标记是在文件的开头的,这时候进行写操作,无疑会把原有的内容给抹掉。由于历史的原因,换行符在不同的系统中有不同模式,比如 在 unix中是一个n,而在windows中是’rn’,用U模式打开文件,就是支持所有的换行模式,也就说’r’ ‘n’ ‘rn’都可表示换行,会有一个tuple用来存贮这个文件中用到过的换行符。不过,虽说换行有多种模式,读到python中统一用n代替。在模式 字符的后面,还可以加上+ b t这两种标识,分别表示可以对文件同时进行读写操作和用二进制模式、文本模式(默认)打开文件。
buffering如果为0表示不进行缓冲;如果为1表示进行”行缓冲”;如果是一个大于1的数表示缓冲区的大小,应该是以字节为单位的。
file对象有自己的属性和方法。先来看看file的属性。
--------------------------------------
closed #标记文件是否已经关闭,由close()改写
encoding #文件编码
mode #打开模式
name #文件名
newlines #文件中用到的换行模式,是一个tuple
softspace #boolean型,一般为0,据说用于print
file的读写方法:
* F.read([size]) #size为读取的长度,以byte为单位
* F.readline([size])
#读一行,如果定义了size,有可能返回的只是一行的一部分
* F.readlines([size])
#把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。
* F.write(str)
#把str写到文件中,write()并不会在str后加上一个换行符
* F.writelines(seq)
#把seq的内容全部写到文件中。这个函数也只是忠实地写入,不会在每行后面加上任何东西。
file的其他方法:
* F.close()
#关闭文件。python会在一个文件不用后自动关闭文件,不过这一功能没有保证,最好还是养成自己关闭的习惯。如果一个文件在关闭后还对其进行操作会产生ValueError
* F.flush()
#把缓冲区的内容写入硬盘
* F.fileno()
#返回一个长整型的”文件标签”
* F.isatty()
#文件是否是一个终端设备文件(unix系统中的)
* F.tell()
#返回文件操作标记的当前位置,以文件的开头为原点
* F.next()
#返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。
* F.seek(offset[,whence])
# 将文件打操作标记移到offset的位置。这个offset一般是相对于文件的开头来计算的,一般为正数。但如果提供了whence参数就不一定了, whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。需要注意,如果文件以a或a+的模式打开,每次进 行写操作时,文件操作标记会自动返回到文件末尾。
* F.truncate([size])
#把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。如果size比文件的大小还要大,依据系统的不同可能是不改变文件,也可能是用0把文件补到相应的大小,也可能是以一些随机的内容加上去。
Time模块:
--------------------------
time() #以浮点形式返回自Linux新世纪以来经过的秒数。在linux中,00:00:00 UTC,
January 1, 1970是新**49**的开始。
>>> time.time()
1150269086.6630149
>>> time.ctime(1150269086.6630149)
>>> 'Wed Jun 14 15:11:26 2006'
time.ctime([sec])#把秒数转换成日期格式,如果不带参数,则显示当前的时间。
>>> import time
>>> time.ctime()
>>> 'Wed Jun 14 15:02:50 2006'
>>> time.ctime(1138068452427683)
'Sat Dec 14 04:51:44 1901'
>>> time.ctime(os.path.getmtime('E:\\untitleds.bmp'))
'Fri Sep 19 16:35:37 2008'
>>> time.gmtime(os.path.getmtime('E:\\untitleds.bmp'))
time.struct_time(tm_year=2008, tm_mon=9, tm_mday=19, tm_hour=8, tm_min=35,
tm_sec=37, tm_wday=4, tm_yday=263, tm_isdst=0)
将一个文件的修改时间转换为日期格式(秒 转 日期)
>>> time.strftime('%Y-%m-%d %X',time.localtime(os.path.getmtime
('E:\\untitleds.bmp')))
'2008-09-19 16:35:37'
#定时3秒。
>>> time.sleep(3)
TIME模块参考:
---------------------------------
#取一个文件的修改时间
>>> os.path.getmtime('E:\\untitleds.bmp')
1221813337.7626641
变量
timezone 通用协调时间和本地标准时间的差值,以秒为单位。
altzone 通用协调时间和本地夏令时的差值
daylight 标志,本地时间是否反映夏令时。
tzname (标准时区名,夏令时时区名)
函数
time() 以浮点数返回纪元至今以来的秒数。
clock() 以浮点数返回CPU开始这个process的时间,(或者至上次调用这个函数的时
间)
sleep() 延迟一段以浮点数表示的秒数。
gmtime() 把以秒表示的时间转换为通用协调时序列
localtime() 把秒时转换为本地时序列
asctime() 将时间序列转换成文本描述
ctime() 将秒时转换成文本描述
mktime() 将本地时序列转换成秒时
strftime() 以指定格式将序列时转为文本描述
strptime() 以指定格式从文本描述中解析出时间序列
tzset() 改变当地时区值
DateTime模块
----------------------------
datetime 将日期转化为秒
-------------------------------------
>>> import datetime,time
>>> time.mktime(datetime.datetime(2009,1,1).timetuple())
1230739200.0
>>> cc=[2000,11,3,12,43,33] #Attributes: year, month, day, hour, minute,
second
>>> time.mktime(datetime.datetime(cc[0],cc[1],cc[2],cc[3],cc[4],cc
[5]).timetuple())
973226613.0
将秒转换为日期格式
>>> cc = time.localtime(os.path.getmtime('E:\\untitleds.bmp'))
>>> print cc[0:3]
(2008, 9, 19)
DateTime示例
-----------------
演示计算两个日期相差天数的计算
>>> import datetime
>>> d1 = datetime.datetime(2005, 2, 16)
>>> d2 = datetime.datetime(2004, 12, 31)
>>> (d1 - d2).days
47
演示计算运行时间的例子,以秒进行显示
import datetime
starttime = datetime.datetime.now()
#long running
endtime = datetime.datetime.now()
print (endtime - starttime).seconds
演示计算当前时间向后10小时的时间。
>>> d1 = datetime.datetime.now()
>>> d3 = d1 + datetime.timedelta(hours=10)
>>> d3.ctime()
其本上常用的类有:datetime和timedelta两个。它们之间可以相互加减。每个类都有一
些方法和属性可以查看具体的值
3)glob
可以使用简单的方法匹配某个目录下的所有子目录或文件,用法也很简单。
3.1 glob.glob(regression) 返回一个列表
3.2 glob.iglob(regression) 返回一个遍历器
这个模块简单好用,强力推荐。
--------------------------
time() #以浮点形式返回自Linux新世纪以来经过的秒数。在linux中,00:00:00 UTC,
January 1, 1970是新**49**的开始。
>>> time.time()
1150269086.6630149
>>> time.ctime(1150269086.6630149)
>>> 'Wed Jun 14 15:11:26 2006'
time.ctime([sec])#把秒数转换成日期格式,如果不带参数,则显示当前的时间。
>>> import time
>>> time.ctime()
>>> 'Wed Jun 14 15:02:50 2006'
>>> time.ctime(1138068452427683)
'Sat Dec 14 04:51:44 1901'
>>> time.ctime(os.path.getmtime('E:\\untitleds.bmp'))
'Fri Sep 19 16:35:37 2008'
>>> time.gmtime(os.path.getmtime('E:\\untitleds.bmp'))
time.struct_time(tm_year=2008, tm_mon=9, tm_mday=19, tm_hour=8, tm_min=35,
tm_sec=37, tm_wday=4, tm_yday=263, tm_isdst=0)
将一个文件的修改时间转换为日期格式(秒 转 日期)
>>> time.strftime('%Y-%m-%d %X',time.localtime(os.path.getmtime
('E:\\untitleds.bmp')))
'2008-09-19 16:35:37'
#定时3秒。
>>> time.sleep(3)
TIME模块参考:
---------------------------------
#取一个文件的修改时间
>>> os.path.getmtime('E:\\untitleds.bmp')
1221813337.7626641
变量
timezone 通用协调时间和本地标准时间的差值,以秒为单位。
altzone 通用协调时间和本地夏令时的差值
daylight 标志,本地时间是否反映夏令时。
tzname (标准时区名,夏令时时区名)
函数
time() 以浮点数返回纪元至今以来的秒数。
clock() 以浮点数返回CPU开始这个process的时间,(或者至上次调用这个函数的时
间)
sleep() 延迟一段以浮点数表示的秒数。
gmtime() 把以秒表示的时间转换为通用协调时序列
localtime() 把秒时转换为本地时序列
asctime() 将时间序列转换成文本描述
ctime() 将秒时转换成文本描述
mktime() 将本地时序列转换成秒时
strftime() 以指定格式将序列时转为文本描述
strptime() 以指定格式从文本描述中解析出时间序列
tzset() 改变当地时区值
DateTime模块
----------------------------
datetime 将日期转化为秒
-------------------------------------
>>> import datetime,time
>>> time.mktime(datetime.datetime(2009,1,1).timetuple())
1230739200.0
>>> cc=[2000,11,3,12,43,33] #Attributes: year, month, day, hour, minute,
second
>>> time.mktime(datetime.datetime(cc[0],cc[1],cc[2],cc[3],cc[4],cc
[5]).timetuple())
973226613.0
将秒转换为日期格式
>>> cc = time.localtime(os.path.getmtime('E:\\untitleds.bmp'))
>>> print cc[0:3]
(2008, 9, 19)
DateTime示例
-----------------
演示计算两个日期相差天数的计算
>>> import datetime
>>> d1 = datetime.datetime(2005, 2, 16)
>>> d2 = datetime.datetime(2004, 12, 31)
>>> (d1 - d2).days
47
演示计算运行时间的例子,以秒进行显示
import datetime
starttime = datetime.datetime.now()
#long running
endtime = datetime.datetime.now()
print (endtime - starttime).seconds
演示计算当前时间向后10小时的时间。
>>> d1 = datetime.datetime.now()
>>> d3 = d1 + datetime.timedelta(hours=10)
>>> d3.ctime()
其本上常用的类有:datetime和timedelta两个。它们之间可以相互加减。每个类都有一
些方法和属性可以查看具体的值
3)glob
可以使用简单的方法匹配某个目录下的所有子目录或文件,用法也很简单。
3.1 glob.glob(regression) 返回一个列表
3.2 glob.iglob(regression) 返回一个遍历器
这个模块简单好用,强力推荐。
1. 9.7 正则表达式与 re 模块
一个正则表达式就是一个用来表示某种模式的字符串。它能帮助你方便的检查一个字符串是否与某种模式匹配。
re 模块使 Python 语言拥有全部的正则表达式功能。 compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。 re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
要精通正则表达式并不容易,而且这本书的主题也不是正则表达式。 本节的目的是教会你在 Python中使用正则表达式。如果要全面的了解正则表达式,我推荐Jeffrey Friedl写的《Mastering Regular Expressions》这本书。这本书全面透彻的讲解了正则表达式的方方面面。
1.1. 9.7.1 模式字符串语法
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于'\\t')匹配相应的特殊字符。
表 9-2 列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。本节后面会提到这些可选的标志。
表 9-2 正则表达式模式语法
元素 含义
. 匹配除换行外的任意字符(如果 DOTALL 则连换行也匹配)
^ 匹配字符串开始(如果MULTILINE,也匹配换行符之后)
$ 匹配字符串结束(如果MULTILINE,也匹配换行符之前)
* 匹配0个或更多个由前面的正则表达式定义的片段,贪婪方式(尽可能多的匹配)
+ 匹配1个或更多个由前面的正则表达式定义的片段,贪婪方式
? 匹配0个或1个由前面的正则表达式定义的片段,贪婪方式
*? , +?, ?? 非贪婪版本的 *, +, 和 ? (尽可能少的匹配)
{m,n} 匹配 m 到 n 次由前面的正则表达式定义的片段,贪婪方式
{m,n}? 匹配 m 到 n 次由前面的正则表达式定义的片段,非贪婪方式
[...] 匹配方括号内内的字符集中的任意一个字符
| 等于 或
(...) 匹配括号内的表达式,也表示一个组
(?iLmsux) 设置可选参数的另类方式,不影响匹配
(?:...) 类似 (...), 但是不表示一个组
(?P...) 类似 (...), 但该组同时得到一个 id,可以在后面的模式中引用
(?P=id) 匹配前面id组匹配的东西
(?#...) 括号内的内容仅仅是注释,不影响匹配
(?=...) Lookahead assertion; matches if regular expression ... matches what comes next, but does not consume any part of the string
(?!...) Negative lookahead assertion; matches if regular expression ... does not match what comes next, and does not consume any part of the string
(?<=...) Lookbehind assertion; matches if there is a match for regular expression ... ending at the current position (... must match a fixed length)
(? \number 匹配先前匹配过的组(通过序号,组自动从1-99编号)
\A 匹配字符串开始
\b 匹配单词边界
\B 匹配一个空串(非单词边界)
\d 匹配任意数字
\D 匹配任意非数字
\s 匹配任意空白字符
\S 匹配任意非空字符
\w 匹配字母数字
\W 匹配非字母数字
\Z 匹配字符串结束
\\ 匹配反斜杠
1.2. 9.7.2 常用正则表达式
'.*' 作为一个正则表达式片段表示 "任意个数(0或更多个)的任意字符(除换行外)"。也就是说, '.*' 匹配一个字符串中的任意子串,包括空串。
'.+' 与'.*'类似,不过它不包括空串。举例来说:
'pre.*post'
匹配一个字符串含有'pre' ,后面跟着一个 'post',中间可以隔着别的字符,也可以不隔着。 (举例来说, 它匹配 'prepost' 和 'pre23post')。
而 'pre.+post' 仅匹配 'pre' 和 'post' 之间有其它字符相隔的情况。(举例来说, 它匹配 'pre23post' 但不匹配 'prepost')。
要强制一个模式仅匹配由 'post' 结尾的字符串,用 \Z 结束这个模式。就象下面这样:
r'pre.*post\Z'
匹配 'prepost', 但不匹配 'preposterous'.
另一个经常用的模式是 \b, 它匹配单词边界. 如果你打算匹配单词 'his' 而不是 'this' 或 'history', 使用下面的正则表达式:
r'\bhis\b'
匹配以 'her' 开头的子串,使用:
r'\bher'
匹配以 'its' 结尾的子串,使用:
r'its\b'
匹配以 'her' 开头的任意单词:
r'\bher\w*'
匹配以 'its' 结尾的任意单词:
r'\w*its\b'
1.3. 9.7.3 字符集合
中括号 ([字符列表]) 用来表示字符集合. 可以用连字符 (-) 来表示连续的数字或字母。最后一个字符也包括在字符集合内,这与 Python range函数不同。中括号内的特殊字符代表他们本身, 除了 \, ], 和 - 之外, 这几个字符你必须转义后才可以代表其本身(通过在其前面放一个反斜线).一个字符集合内,你可以使用转义字符所表示的字符类,如 \d 或 \S 等.不过字符集合内的 \b 表示一个退格字符( backspace ), 而不是一个单词边界. 如果一个字符集合里的第一个字符是尖号 (^), 这个集合就是反集合,也就是说.这个集合匹配尖号后面的字符之外的任何字符.
一个常用集合用来匹配单词(字母,连字符或省略符(单引号)):
r"[a-zA-z'\-]+"
连字符前的转义反斜框在此处不是必需的,因为连字符所在位置使它不会具有歧义性.不过还是建议你一直对其使用转义符号,这会使你的模式字符串可读性更佳.
1.4. 9.7.4 可选择的匹配
竖线 (|) 表明竖线两边的匹配可以任选其一, 具有较低的优先级。. 如果不使用括号, | 则对其两边的整个模式起作用,直到遇到字符串起始或结束或另一个 | 符号为止.一个模式可以由任意个由 | 符号连接的子模式组成.要匹配一个这样的表达式,第一个子模式首先尝试匹配,如果匹配成功,其它的就被跳过.否则就尝试第二个,...第三个.... | 既是贪婪的又是非贪婪的,因为它根本不关心匹配长度.
如果你有一个单词的列表 L , 匹配任意单词的正则表达式就是:
'|'.join([r'\b%s\b' % word for word in L])
如果 L 的元素是常规字符串,而不仅仅是单词, 你需要用 re.escape(本章后面会有详述) 来转义它们. 如果你不需要 \b 单词边界,那么下面这个正则表达式就能满足你的需要:
'|'.join(map(re.escape,L))
1.5. 9.7.5 分组
正则表达式可以包含0至99个分组(允许任意个,但只有前99个被支持)。通常模式字符串中的一对未转义的小括号表示一个分组。元素 (?P...) 也表示一个分组,不同的是它还给这个分组指定了一个名字, id, 可以是任意的 Python 标识符。所有的分组,命名的或未命名的,均被从左至右编号( 1 至 99), 组号 0 表示整个正则表达式。
对一个字符串的任意正则表达式匹配, 每个分组匹配一个子串 (也可能是一个空串)。 当一个正则表达式使用 | 时, 某些分组可能不匹配任何子串,尽管整个正则表达式是匹配的。当一个分组的匹配是一个空串时,我们称这种情形为该分组没有参与匹配。 举例来说:
r'(.+)\1+\Z'
该模式匹配任意非空子串的两个或更多个重复。(.+) 匹配一个非空子串 (任意字符任意个), 并且定义了一个分组。 \1+ 部分匹配1至更多次这个分组的重复。\Z 将匹配限制只允许发生在字符串的结尾。
1.6. 9.7.6 选项
除了在 re 模块的 compile 函数中提供 flags 选项参数之外,在 (? 和 ) 之间使用"iLmsux" 中的一个或多个字母能让你可以在模式字符串中设置正则表达式选项。不论哪种方式设置的选项,都是针对整个正则表达式的。为了清晰起见,选项通常总是放在模式的开头。如果使用选项x,则选项必须放置在模式首部,因为x选项影响Python解析模式的方式。
显式的使用选项参数比起将选项参数放在模式字符串中具有更好的可读性。函数 compile 的 flags 参数是一个整数, 通过对re模块中提供的属性中的一个或几个进行 '按位或' 运算得来。 (with Python's bitwise OR operator, |). 为了书写方便,每个属性都有一个简称 (一个大写字母)和一个全名 (一个全大写的标识符,具有更好的可读性)。
I 或 IGNORECASE 匹配忽略时大小写
L 或 LOCALE 让 \w, \W, \b, 和 \B 由当前区域设置决定
M 或 MULTILINE 特殊符号 ^ 和 $ 除了匹配字符串开始和结尾,也匹配每行的开始和结尾 (换行符之后/之前)
S 或 DOTALL 特殊字符 . 匹配任意字符,包括换行符
U 或 UNICODE \w, \W, \b, 和 \B 由Unicode字符集决定
X 或 VERBOSE 忽略模式字符串中的空白字符, 除非被转义的空白或空白位于字符集合内(中括号内)。该方式允许用 # 字符添加注释直至行尾。
举个例子,下面用三种不同的方式通过 compile 函数生成了相同的三个正则表达式对象(均与不区分大小写的'hello'模式匹配):
Toggle line numbers Toggle line numbers
1 import re
2 r1 = re.compile(r'(?i)hello')
3 r2 = re.compile(r'hello', re.I)
4 r3 = re.compile(r'hello', re.IGNORECASE)
第三种方式清晰易读,容易维护,尽管它写起来麻烦一点点。注意虽然在这里使用原始字符串不太必要(没有使用转义字符),不过仍然推荐你一直在书写模式字符串时使用原始字符串。
选项 re.VERBOSE (或 re.X) 允许你通过在模式字符串中添加适当的空白和注释来使得正则表达式更容易阅读和维护。复杂的模式可以写成多行,并且能够为每一行添加注释。因此在这种模式你最好使用三引号字符串来书写模式字符串。举例来说:
repat_num1 = r'(0[0-7]*|0x[\da-fA-F]+|[1-9]\d*)L?\Z'
repat_num2 = r'''(?x) # 该模式用来匹配整数
(0 [0-7]* | # 八进制: 前导 0, 0+ 个八进制数字
0x [\da-f-A-F]+ | # 十六进制: 0x, 1+ 十六进制数字
[1-9] \d* ) # 十进制: 前导数字(非0), 0+ 十进制数字
L?\Z # 可有可无的L, 位于字符串结尾
'''
该例子中的两个模式是完全同义的。但是第二个因为添加了注释并且合理的使用了空白,因此具有更好的可读性和可维护性。
1.7. 9.7.7 Match VS Search
到目前为止,我们已经学会了使用正则表达式来匹配字符串。如果用 match方法,正则表达式模式 r'box' 匹配字符串 'box' 和 'boxes', 但是不匹配 'inbox'. 也就是说,正则表达式对象的 match 方法总是默认匹配从字符串的起始位置开始匹配。就象模式字符串的第一个元素是 \A 一样。
通常,你可能关心发生在字符串的任意位置的匹配,而不是仅发生在字符串首部的匹配。Python管这种操作叫做 Search ,这是为了和 match 有所区别而取的新术语。要进行 search ,你只需要简单的使用正则表达式对象的 search 方法就可以了。看下面的例子:
Toggle line numbers Toggle line numbers
1 import re
2 r1 = re.compile(r'box')
3 if r1.match('inbox'): print 'match succeeds'
4 else print 'match fails' # prints: match fails
5 if r1. search('inbox'): print 'search succeeds' # prints: search succeeds
6 else print 'search fails'
1.8. 9.7.8 字符串开始和结束
\A and \Z 分别用来表示字符串的开始和结束。传统上使用 ^ 代表字符串开始, $ 代表字符串结束. 在非多行方式下,^ 等于 \A, $ 等于 \Z。(模式串中没有 ?m 并且没有使用标志 re.M 或 re.MULTILINE进行编译).对一个多行正则表达式对象来说, ^ 代表任意行的开始 (可能是字符串开始,也可能是一个换行符之后). 类似的, $ 代表任意行的结束(可能是字符串的结束,也可能是一个换行符之前). \A 和 \Z 无论是否多行方式,总是严格匹配字符串的开始和结束。举例来说:下面的代码检查一个文件中是否有以数字结束的行。
Toggle line numbers Toggle line numbers
1 import re
2 digatend = re.compile(r'\d
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers Toggle line numbers
1 import re
2 reword = re.compile(r'\w+')
3 for aword in reword.findall(open('afile.txt').read( )):
4 print aword
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
reword = re.compile('(\w+)\s')
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers Toggle line numbers
1 import re
2 first_last = re.compile(r'^\W*(\w+)\b.*\b(\w+)\W*
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers Toggle line numbers
1 import re
2 digs = re.compile(r'\d+')
3 for line in open('afile.txt'):
4 if digs.match(line): print line,
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers Toggle line numbers
1 import re
2 digs = re.compile(r'\d+')
3 for line in open('afile.txt'):
4 if digs.search(line): print line,
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 astring = ''.join(rehello.split(astring))
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers Toggle line numbers
1 import re
2 re_col_ws_dig = re.compile(r'(:)\s+(\d)')
3 astring = ''.join(re_col_ws_dig.split(astring))
这个例子可以说明更多问题:
>>> pat=r'(abc):(123)4(56)'
>>> r=re.compile(pat)
>>> s='aaabc:123456defghikabc:123456lll'
>>> r.split(s)
['aa', 'abc', '123', '56', 'defghik', 'abc', '123', '56', 'lll']
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
astring = ''.join(rehello.split(astring, 1))
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 astring = rehello.sub('', astring, 1)
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers Toggle line numbers
1 import re
2 h_word = re.compile(r'\bh\w+o\b', re.IGNORECASE)
3 def up(mo): return mo.group(0).upper( )
4 astring = h_word.sub(up, astring)
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers Toggle line numbers
1 import re
2 def findall(r, s):
3 result = [ ]
4 def foundOne(mo): result.append(mo.group( ))
5 r.sub(foundOne, s)
6 return result
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers Toggle line numbers
1 import re
2 grouped_word = re.compile('(\w+)')
3 astring = grouped_word.sub(r'{\1}', astring)
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 junk, count = rehello.subn('', astring)
4 print 'Found', count, 'occurrences of "hello"'
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers Toggle line numbers
1 import re
2 junk, count = re.subn(r'(?i)hello', '', astring)
3 print 'Found', count, 'occurrences of "hello"'
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 if re.search(open('afile.txt').read()): print "some lines end with digits" 4 else: print "no lines end with digits"
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers
___FCKpd___5
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
___FCKpd___6
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers
___FCKpd___7
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 for first, last in first_last.findall(open('afile.txt').read( )): 4 print first, last
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 if re.search(open('afile.txt').read()): print "some lines end with digits" 4 else: print "no lines end with digits"
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers
___FCKpd___5
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
___FCKpd___6
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers
___FCKpd___7
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
一个正则表达式就是一个用来表示某种模式的字符串。它能帮助你方便的检查一个字符串是否与某种模式匹配。
re 模块使 Python 语言拥有全部的正则表达式功能。 compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。 re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
要精通正则表达式并不容易,而且这本书的主题也不是正则表达式。 本节的目的是教会你在 Python中使用正则表达式。如果要全面的了解正则表达式,我推荐Jeffrey Friedl写的《Mastering Regular Expressions》这本书。这本书全面透彻的讲解了正则表达式的方方面面。
1.1. 9.7.1 模式字符串语法
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于'\\t')匹配相应的特殊字符。
表 9-2 列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。本节后面会提到这些可选的标志。
表 9-2 正则表达式模式语法
元素 含义
. 匹配除换行外的任意字符(如果 DOTALL 则连换行也匹配)
^ 匹配字符串开始(如果MULTILINE,也匹配换行符之后)
$ 匹配字符串结束(如果MULTILINE,也匹配换行符之前)
* 匹配0个或更多个由前面的正则表达式定义的片段,贪婪方式(尽可能多的匹配)
+ 匹配1个或更多个由前面的正则表达式定义的片段,贪婪方式
? 匹配0个或1个由前面的正则表达式定义的片段,贪婪方式
*? , +?, ?? 非贪婪版本的 *, +, 和 ? (尽可能少的匹配)
{m,n} 匹配 m 到 n 次由前面的正则表达式定义的片段,贪婪方式
{m,n}? 匹配 m 到 n 次由前面的正则表达式定义的片段,非贪婪方式
[...] 匹配方括号内内的字符集中的任意一个字符
| 等于 或
(...) 匹配括号内的表达式,也表示一个组
(?iLmsux) 设置可选参数的另类方式,不影响匹配
(?:...) 类似 (...), 但是不表示一个组
(?P...) 类似 (...), 但该组同时得到一个 id,可以在后面的模式中引用
(?P=id) 匹配前面id组匹配的东西
(?#...) 括号内的内容仅仅是注释,不影响匹配
(?=...) Lookahead assertion; matches if regular expression ... matches what comes next, but does not consume any part of the string
(?!...) Negative lookahead assertion; matches if regular expression ... does not match what comes next, and does not consume any part of the string
(?<=...) Lookbehind assertion; matches if there is a match for regular expression ... ending at the current position (... must match a fixed length)
(? \number 匹配先前匹配过的组(通过序号,组自动从1-99编号)
\A 匹配字符串开始
\b 匹配单词边界
\B 匹配一个空串(非单词边界)
\d 匹配任意数字
\D 匹配任意非数字
\s 匹配任意空白字符
\S 匹配任意非空字符
\w 匹配字母数字
\W 匹配非字母数字
\Z 匹配字符串结束
\\ 匹配反斜杠
1.2. 9.7.2 常用正则表达式
'.*' 作为一个正则表达式片段表示 "任意个数(0或更多个)的任意字符(除换行外)"。也就是说, '.*' 匹配一个字符串中的任意子串,包括空串。
'.+' 与'.*'类似,不过它不包括空串。举例来说:
'pre.*post'
匹配一个字符串含有'pre' ,后面跟着一个 'post',中间可以隔着别的字符,也可以不隔着。 (举例来说, 它匹配 'prepost' 和 'pre23post')。
而 'pre.+post' 仅匹配 'pre' 和 'post' 之间有其它字符相隔的情况。(举例来说, 它匹配 'pre23post' 但不匹配 'prepost')。
要强制一个模式仅匹配由 'post' 结尾的字符串,用 \Z 结束这个模式。就象下面这样:
r'pre.*post\Z'
匹配 'prepost', 但不匹配 'preposterous'.
另一个经常用的模式是 \b, 它匹配单词边界. 如果你打算匹配单词 'his' 而不是 'this' 或 'history', 使用下面的正则表达式:
r'\bhis\b'
匹配以 'her' 开头的子串,使用:
r'\bher'
匹配以 'its' 结尾的子串,使用:
r'its\b'
匹配以 'her' 开头的任意单词:
r'\bher\w*'
匹配以 'its' 结尾的任意单词:
r'\w*its\b'
1.3. 9.7.3 字符集合
中括号 ([字符列表]) 用来表示字符集合. 可以用连字符 (-) 来表示连续的数字或字母。最后一个字符也包括在字符集合内,这与 Python range函数不同。中括号内的特殊字符代表他们本身, 除了 \, ], 和 - 之外, 这几个字符你必须转义后才可以代表其本身(通过在其前面放一个反斜线).一个字符集合内,你可以使用转义字符所表示的字符类,如 \d 或 \S 等.不过字符集合内的 \b 表示一个退格字符( backspace ), 而不是一个单词边界. 如果一个字符集合里的第一个字符是尖号 (^), 这个集合就是反集合,也就是说.这个集合匹配尖号后面的字符之外的任何字符.
一个常用集合用来匹配单词(字母,连字符或省略符(单引号)):
r"[a-zA-z'\-]+"
连字符前的转义反斜框在此处不是必需的,因为连字符所在位置使它不会具有歧义性.不过还是建议你一直对其使用转义符号,这会使你的模式字符串可读性更佳.
1.4. 9.7.4 可选择的匹配
竖线 (|) 表明竖线两边的匹配可以任选其一, 具有较低的优先级。. 如果不使用括号, | 则对其两边的整个模式起作用,直到遇到字符串起始或结束或另一个 | 符号为止.一个模式可以由任意个由 | 符号连接的子模式组成.要匹配一个这样的表达式,第一个子模式首先尝试匹配,如果匹配成功,其它的就被跳过.否则就尝试第二个,...第三个.... | 既是贪婪的又是非贪婪的,因为它根本不关心匹配长度.
如果你有一个单词的列表 L , 匹配任意单词的正则表达式就是:
'|'.join([r'\b%s\b' % word for word in L])
如果 L 的元素是常规字符串,而不仅仅是单词, 你需要用 re.escape(本章后面会有详述) 来转义它们. 如果你不需要 \b 单词边界,那么下面这个正则表达式就能满足你的需要:
'|'.join(map(re.escape,L))
1.5. 9.7.5 分组
正则表达式可以包含0至99个分组(允许任意个,但只有前99个被支持)。通常模式字符串中的一对未转义的小括号表示一个分组。元素 (?P...) 也表示一个分组,不同的是它还给这个分组指定了一个名字, id, 可以是任意的 Python 标识符。所有的分组,命名的或未命名的,均被从左至右编号( 1 至 99), 组号 0 表示整个正则表达式。
对一个字符串的任意正则表达式匹配, 每个分组匹配一个子串 (也可能是一个空串)。 当一个正则表达式使用 | 时, 某些分组可能不匹配任何子串,尽管整个正则表达式是匹配的。当一个分组的匹配是一个空串时,我们称这种情形为该分组没有参与匹配。 举例来说:
r'(.+)\1+\Z'
该模式匹配任意非空子串的两个或更多个重复。(.+) 匹配一个非空子串 (任意字符任意个), 并且定义了一个分组。 \1+ 部分匹配1至更多次这个分组的重复。\Z 将匹配限制只允许发生在字符串的结尾。
1.6. 9.7.6 选项
除了在 re 模块的 compile 函数中提供 flags 选项参数之外,在 (? 和 ) 之间使用"iLmsux" 中的一个或多个字母能让你可以在模式字符串中设置正则表达式选项。不论哪种方式设置的选项,都是针对整个正则表达式的。为了清晰起见,选项通常总是放在模式的开头。如果使用选项x,则选项必须放置在模式首部,因为x选项影响Python解析模式的方式。
显式的使用选项参数比起将选项参数放在模式字符串中具有更好的可读性。函数 compile 的 flags 参数是一个整数, 通过对re模块中提供的属性中的一个或几个进行 '按位或' 运算得来。 (with Python's bitwise OR operator, |). 为了书写方便,每个属性都有一个简称 (一个大写字母)和一个全名 (一个全大写的标识符,具有更好的可读性)。
I 或 IGNORECASE 匹配忽略时大小写
L 或 LOCALE 让 \w, \W, \b, 和 \B 由当前区域设置决定
M 或 MULTILINE 特殊符号 ^ 和 $ 除了匹配字符串开始和结尾,也匹配每行的开始和结尾 (换行符之后/之前)
S 或 DOTALL 特殊字符 . 匹配任意字符,包括换行符
U 或 UNICODE \w, \W, \b, 和 \B 由Unicode字符集决定
X 或 VERBOSE 忽略模式字符串中的空白字符, 除非被转义的空白或空白位于字符集合内(中括号内)。该方式允许用 # 字符添加注释直至行尾。
举个例子,下面用三种不同的方式通过 compile 函数生成了相同的三个正则表达式对象(均与不区分大小写的'hello'模式匹配):
Toggle line numbers Toggle line numbers
1 import re
2 r1 = re.compile(r'(?i)hello')
3 r2 = re.compile(r'hello', re.I)
4 r3 = re.compile(r'hello', re.IGNORECASE)
第三种方式清晰易读,容易维护,尽管它写起来麻烦一点点。注意虽然在这里使用原始字符串不太必要(没有使用转义字符),不过仍然推荐你一直在书写模式字符串时使用原始字符串。
选项 re.VERBOSE (或 re.X) 允许你通过在模式字符串中添加适当的空白和注释来使得正则表达式更容易阅读和维护。复杂的模式可以写成多行,并且能够为每一行添加注释。因此在这种模式你最好使用三引号字符串来书写模式字符串。举例来说:
repat_num1 = r'(0[0-7]*|0x[\da-fA-F]+|[1-9]\d*)L?\Z'
repat_num2 = r'''(?x) # 该模式用来匹配整数
(0 [0-7]* | # 八进制: 前导 0, 0+ 个八进制数字
0x [\da-f-A-F]+ | # 十六进制: 0x, 1+ 十六进制数字
[1-9] \d* ) # 十进制: 前导数字(非0), 0+ 十进制数字
L?\Z # 可有可无的L, 位于字符串结尾
'''
该例子中的两个模式是完全同义的。但是第二个因为添加了注释并且合理的使用了空白,因此具有更好的可读性和可维护性。
1.7. 9.7.7 Match VS Search
到目前为止,我们已经学会了使用正则表达式来匹配字符串。如果用 match方法,正则表达式模式 r'box' 匹配字符串 'box' 和 'boxes', 但是不匹配 'inbox'. 也就是说,正则表达式对象的 match 方法总是默认匹配从字符串的起始位置开始匹配。就象模式字符串的第一个元素是 \A 一样。
通常,你可能关心发生在字符串的任意位置的匹配,而不是仅发生在字符串首部的匹配。Python管这种操作叫做 Search ,这是为了和 match 有所区别而取的新术语。要进行 search ,你只需要简单的使用正则表达式对象的 search 方法就可以了。看下面的例子:
Toggle line numbers Toggle line numbers
1 import re
2 r1 = re.compile(r'box')
3 if r1.match('inbox'): print 'match succeeds'
4 else print 'match fails' # prints: match fails
5 if r1. search('inbox'): print 'search succeeds' # prints: search succeeds
6 else print 'search fails'
1.8. 9.7.8 字符串开始和结束
\A and \Z 分别用来表示字符串的开始和结束。传统上使用 ^ 代表字符串开始, $ 代表字符串结束. 在非多行方式下,^ 等于 \A, $ 等于 \Z。(模式串中没有 ?m 并且没有使用标志 re.M 或 re.MULTILINE进行编译).对一个多行正则表达式对象来说, ^ 代表任意行的开始 (可能是字符串开始,也可能是一个换行符之后). 类似的, $ 代表任意行的结束(可能是字符串的结束,也可能是一个换行符之前). \A 和 \Z 无论是否多行方式,总是严格匹配字符串的开始和结束。举例来说:下面的代码检查一个文件中是否有以数字结束的行。
Toggle line numbers Toggle line numbers
1 import re
2 digatend = re.compile(r'\d
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers Toggle line numbers
1 import re
2 reword = re.compile(r'\w+')
3 for aword in reword.findall(open('afile.txt').read( )):
4 print aword
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
reword = re.compile('(\w+)\s')
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers Toggle line numbers
1 import re
2 first_last = re.compile(r'^\W*(\w+)\b.*\b(\w+)\W*
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers Toggle line numbers
1 import re
2 digs = re.compile(r'\d+')
3 for line in open('afile.txt'):
4 if digs.match(line): print line,
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers Toggle line numbers
1 import re
2 digs = re.compile(r'\d+')
3 for line in open('afile.txt'):
4 if digs.search(line): print line,
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 astring = ''.join(rehello.split(astring))
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers Toggle line numbers
1 import re
2 re_col_ws_dig = re.compile(r'(:)\s+(\d)')
3 astring = ''.join(re_col_ws_dig.split(astring))
这个例子可以说明更多问题:
>>> pat=r'(abc):(123)4(56)'
>>> r=re.compile(pat)
>>> s='aaabc:123456defghikabc:123456lll'
>>> r.split(s)
['aa', 'abc', '123', '56', 'defghik', 'abc', '123', '56', 'lll']
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
astring = ''.join(rehello.split(astring, 1))
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 astring = rehello.sub('', astring, 1)
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers Toggle line numbers
1 import re
2 h_word = re.compile(r'\bh\w+o\b', re.IGNORECASE)
3 def up(mo): return mo.group(0).upper( )
4 astring = h_word.sub(up, astring)
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers Toggle line numbers
1 import re
2 def findall(r, s):
3 result = [ ]
4 def foundOne(mo): result.append(mo.group( ))
5 r.sub(foundOne, s)
6 return result
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers Toggle line numbers
1 import re
2 grouped_word = re.compile('(\w+)')
3 astring = grouped_word.sub(r'{\1}', astring)
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers Toggle line numbers
1 import re
2 rehello = re.compile(r'hello', re.IGNORECASE)
3 junk, count = rehello.subn('', astring)
4 print 'Found', count, 'occurrences of "hello"'
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers Toggle line numbers
1 import re
2 junk, count = re.subn(r'(?i)hello', '', astring)
3 print 'Found', count, 'occurrences of "hello"'
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 if re.search(open('afile.txt').read()): print "some lines end with digits" 4 else: print "no lines end with digits"
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers
___FCKpd___5
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
___FCKpd___6
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers
___FCKpd___7
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 for first, last in first_last.findall(open('afile.txt').read( )): 4 print first, last
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
, re.MULTILINE) 3 if re.search(open('afile.txt').read()): print "some lines end with digits" 4 else: print "no lines end with digits"
模式 r'\d\n' 几乎与r'\d$'同义, 但是当一个文件以数字却没有回车结尾时,匹配将会失败。
1.9. 9.7.9 正则表达式对象
正则表达式对象 r 拥有下列只读属性, 这些属性详细描述了 r 是被如何创建出来的。 (通过模块 re 中的 compile 函数,见后文):
1.9.1. flags
传递给 compile 函数的 flags 参数, 如果省略了 flags 参数则为 0
1.9.2. groupindex
一个字典,它的 key 是通过元素(?P)定义的组的名字; 相应的值则是该组的序号。
1.9.3. pattern
编译 r 使用的模式字符串
这些属性让你很容易的重新得到该对象被编译时使用的模式字符串和参数,再也不需要将它们保存到一个单独地方了了。
正则表达式对象 r 同样提供了很多方法来定位一个字符串中的正则表达式的匹配, 以便进行替换或其它操作,匹配通常由特殊对象表示, 9.7.10节会详细介绍.
1.9.4. findall 方法
r.findall(s)
当 r 没有分组时, findall 返回一个字符串列表, 每个字符串都是 s 中不重叠的 r 的匹配. 下面的例子演示了如何打印出一个文件中的所有单词:
Toggle line numbers
___FCKpd___5
当 r 有一个分组时, findall 也返回一个字符串列表,列表中的每个字符串都是这个分组的匹配. 举例来说,如果你希望打印出所有的单词(不包括标点),你只需要在上面的例子里修改一个语句:
___FCKpd___6
当 r 有 n 个分组时 ( n > 1), findall 返回一个tuple的列表, 包括每一个不重叠的匹配. 每个tuple 有 n 个元素, 每个元素对应一个分组. 下面的例子打印出每行的第一个和最后一个单词(当然是匹配至少有两个单词的行).
Toggle line numbers
___FCKpd___7
1.9.5. match 方法
r.match(s,start=0,end=sys.maxint)
当匹配时,返回一个 match 对象,否则返回 None. 注意这个匹配严格的从字符串的 start 位置开始. 要在整个字符串中向前搜索匹配,使用 r.search 而不是 r.match. 下面的例子演示了如何打印出一个文件中所有以数字开头的行:
Toggle line numbers
___FCKpd___8
1.9.6. search 方法
r.search(s,start=0,end=sys.maxint)
如果匹配成功,返回一个匹配最左边子串的 match 对象,否则返回 None.下面的例子演示了如何打印出含有数字的行:
Toggle line numbers
___FCKpd___9
1.9.7. split 方法
r.split(s,maxsplit=0)
返回一个该匹配分隔的子串列表.举例来说,要排除一个字符串中所有的 'hello' 不区分大小写,可以这样:
Toggle line numbers
___FCKpd___10
如果 r 有多个分组,则分隔的规则就会象下面这样。下面这个例子只删除位于一个冒号(:)和数字之间的空白。
Toggle line numbers
___FCKpd___11
这个例子可以说明更多问题:
___FCKpd___12
若 maxsplit 大于 0, 则至多进行 maxsplit 次分隔,剩下的部分则成为列表的最后一个元素。下面的例子只删除第一个匹配的'hello':
___FCKpd___13
1.9.8. sub 函数
r.sub(repl,s,count=0)
返回字符串s的一个拷贝,该串中的所有匹配均被替换成了 repl 。repl可以是一个字符串或一个可调用对象(函数或别的东西)。仅当不存在前一个匹配时,使用空的匹配(空串)替换. 当 count 大于 0 时, 只有前 count 个匹配被替换。若 count 等于 0, 所有的匹配都被替换. 下面的例子提供了删除目的字符串中第一次出现的 'hello' (不区分大小写)的另外一种方式:
Toggle line numbers
___FCKpd___14
如果例子中的 sub 方法没有最后一个参数, 则例子中的字符串 astring 中的所有 'hello' 均被删除。
若 repl 是一个可调用对象, repl 必须接受且仅接受一个 match 对象做为参数,并返回用来替换匹配的字符串。 sub 调用 repl, 并提供给 repl 一个合适的 match-object 参数, repl则为每个匹配返回一个替换值。还是举个例子表述的清楚,要将所有首字母为'h',末字母为 'o' 的匹配单词转化为大写,你可以这么做:
Toggle line numbers
___FCKpd___15
在你不需要对匹配进行替换而是需要对这些匹配进行更复杂的处理时,sub 方法非常有用. 下面这个例子展示了 sub 方法的使用,它用来对一个没有分组的正则表达式生成一个类似 findall 方法的函数.
Toggle line numbers
___FCKpd___16
这个例子需要 Python 2.2 或更高, 不仅仅是因为它使用了嵌套作用域, 更大的原因是 Python 2.2 允许 repl 返回None并且视为其返回一个空串(). 而 Python 2.1则太轴,在Python2.1中,只允许 repl 返回一个字符串.
若 repl 是一个字符串而且它不是一个向后引用时, sub 使用 repl 自身作为替换.向后引用是一个 \g 形式的 repl 子串,这里 id 是 r 中一个分组的名字(由 r 中模式字符串中的 (?P) 建立), 或 \dd, 这里 dd 是一个或两个数字,代表一个分组的编号. 每个向后引用,不论是命名的还是编号的, 都被其所代码的匹配内容所替换.举例来说,下面这个将每个单词放入大括号中:
Toggle line numbers
___FCKpd___17
1.9.9. subn 函数
r.subn(repl,s,count=0)
subn 与 sub 相同, 只是 subn 返回一个元组 (new_string, n) ,这里 n 是 subn 替换的数字.看这个例子, 要统计子串'hello'出现的次数,一个方法是:
Toggle line numbers
___FCKpd___18
1.10. 9.7.10 Match 对象
正则表达式对象的 match 和 search 方法创建并返回 Match 对象. 当 repl 参数为可调用对象时, sub 及 subn 方法也会在幕后悄悄生成 Match 对象并使用.(在那种情况下一个相应的 match 对象被作为实参传递给 repl 对象.一个match 对象 m 支持以下属性:
pos 起始位置. 传递给 match 或 search 对象的开始位置参数(也就是字符串s开始匹配位置)
endpos 结束位置.传递给 match 或 search 对象的结束位置参数(也就是字符串s结束匹配位置)
lastgroup 最后匹配的分组的名字(或分组没有名字或根本没有匹配,返回None)
lastindex 最后匹配的分组的整数索引(从1开始). (如果没有匹配返回 None)
re 创建 m 对象的方法所属的正则表达式对象.
string 传递给方法 match, search, sub, 或 subn 的字符串 s
一个 match 对象也支持以下方法:
1.10.1. end, span, start 方法
m.end(groupid=0)
m.span(groupid=0)
m.start(groupid=0)
这些方法返回 m.string 中的由groupid 确定的分组所匹配的子串的定界索引.这里 groupid 可以是一个分组的编号或名字. 当匹配子串是 m.string[i:j] 时, m.start 返回 i, m.end 返回 j, m.span 返回 (i, j). 当分组没有匹配时, i 和 j 的值为 -1.
1.10.2. expand 方法
m.expand(s)
返回 s 的一个拷贝, 其中转义序列和向后引用以和 r.sub 同样的方式进行了了替换. 前一小节有详述.
1.10.3. group 方法
m.group(groupid=0,*groupids)
当以一个单一的 groupid 参数(一个分组编号或名字)调用时, m.group 返回匹配该分组的子串或 None(没有匹配时). 一个惯用的方式就是 m.group( ), 也就是 m.group(0), 返回整个匹配子串(group 编号 0 暗指整个正则表达式).
当以多参数的方式调用时, 每个参数必须是一个分组编号或分组名字. 这时 m.group 就返回一个tuple(每个元素对应一个参数), 元素的是匹配相应分组的子串或 None (未发生匹配时).
1.10.4. groups 方法
m.groups(default=None)
返回一个tuple,tuple的每个元素分别是模式中的分组。如果匹配失败,则返回 none.
1.10.5. groupdict 方法
m.groupdict(default=None)
返回一个 key 为表达式 r 中的命名分组名字的一个字典. 每个名字的值是相应的匹配子串,或者在未有匹配时 default 的值.
1.11. 9.7.11 模块 re 中的函数
模块 re 不仅提供了 9.7.6 节中的属性,它还提供了与正则表达式对象的每个方法功能相同的函数。(findall, match, search, split, sub, and subn), 这些函数的第一个参数就是模式字符串。显然这些函数内部也是将这个模式字符串编译为正则表达式对象后再处理的。通常显示的将模式字符串编译为正则表达式对象然后调用该对象的方式更好些,不过,对于某些模式的一次性使用,使用函数更方便一些。举例来说,统计'hello'在一个字符串中出现的次数(不区分大小写),象下面这样做:
Toggle line numbers
___FCKpd___19
象上面这种方式使用正则表达式,正则表达式选项必须内嵌在模式字符串内(例如在这个例子里的大小写不敏感选项,即(?i)),这是因为这些函数被设计成不接受标志选项参数。
模块 re 也提供了错误处理,当发生错误时会引发异常(通常都是模式字符串的语法错误)。 re模块还提供了两个另外的函数:
1.11.1. compile 函数
compile(pattern,flags=0)
解析模式字符串中的每一个语法元素,若无错误则创建并返回一个正则表达式对象。
1.11.2. escape 函数
escape(s)
返回一个字符串s的拷贝,不过s中的所有非字母数字字符在新串中均已被转义(在其前面添加反斜杠)。
copy(src, dst)
Copy data and mode bits ("cp src dst").
The destination may be a directory.
copy2(src, dst)
Copy data and all stat info ("cp -p src dst").
The destination may be a directory.
copyfile(src, dst)
Copy data from src to dst
copyfileobj(fsrc, fdst, length=16384)
copy data from file-like object fsrc to file-like object fdst
copymode(src, dst)
Copy mode bits from src to dst
copystat(src, dst)
Copy all stat info (mode bits, atime and mtime) from src to dst
copytree(src, dst, symlinks=False)
Recursively copy a directory tree using copy2().
The destination directory must not already exist.
If exception(s) occur, an Error is raised with a list of reasons.
If the optional symlinks flag is true, symbolic links in the
source tree result in symbolic links in the destination tree; if
it is false, the contents of the files pointed to by symbolic
links are copied.
XXX Consider this example code rather than the ultimate tool.
move(src, dst)
Recursively move a file or directory to another location.
If the destination is on our current filesystem, then simply use
rename. Otherwise, copy src to the dst and then remove src.
A lot more could be done here... A look at a mv.c shows a lot of
the issues this implementation glosses over.
rmtree(path, ignore_errors=False, onerror=None)
Recursively delete a directory tree.
If ignore_errors is set, errors are ignored; otherwise, if onerror
is set, it is called to handle the error with arguments (func,
path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
path is the argument to that function that caused it to fail; and
exc_info is a tuple returned by sys.exc_info(). If ignore_errors
is false and onerror is None, an exception is raised.
Copy data and mode bits ("cp src dst").
The destination may be a directory.
copy2(src, dst)
Copy data and all stat info ("cp -p src dst").
The destination may be a directory.
copyfile(src, dst)
Copy data from src to dst
copyfileobj(fsrc, fdst, length=16384)
copy data from file-like object fsrc to file-like object fdst
copymode(src, dst)
Copy mode bits from src to dst
copystat(src, dst)
Copy all stat info (mode bits, atime and mtime) from src to dst
copytree(src, dst, symlinks=False)
Recursively copy a directory tree using copy2().
The destination directory must not already exist.
If exception(s) occur, an Error is raised with a list of reasons.
If the optional symlinks flag is true, symbolic links in the
source tree result in symbolic links in the destination tree; if
it is false, the contents of the files pointed to by symbolic
links are copied.
XXX Consider this example code rather than the ultimate tool.
move(src, dst)
Recursively move a file or directory to another location.
If the destination is on our current filesystem, then simply use
rename. Otherwise, copy src to the dst and then remove src.
A lot more could be done here... A look at a mv.c shows a lot of
the issues this implementation glosses over.
rmtree(path, ignore_errors=False, onerror=None)
Recursively delete a directory tree.
If ignore_errors is set, errors are ignored; otherwise, if onerror
is set, it is called to handle the error with arguments (func,
path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
path is the argument to that function that caused it to fail; and
exc_info is a tuple returned by sys.exc_info(). If ignore_errors
is false and onerror is None, an exception is raised.




