Created
November 21, 2012 06:51
-
-
Save songxiaofeng1981/4123464 to your computer and use it in GitHub Desktop.
python:regrex-explain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
#encoding=utf-8 | |
#vim ft=python | |
#abstract: 演示Python中正则表达式的基本用法 | |
#tag:Python RegExp example | |
import re | |
#辅助函数,打印一个matchobject的信息 | |
def print_match(s, m): | |
if m: | |
#group()函数返回指定group的内容,默认参数0返回整个匹配,非0的参数表示子匹配 | |
print s, '\tmatchobject:', m.group() | |
else: | |
print s, '\tnot match' | |
def test1(): | |
s = 'hello world' | |
r1 = 'h.*l' | |
r2 = '.*l' | |
#re.match和re.search的区别 | |
#re.match必须从字符串第一个字符开始匹配,re.search可以从中间任意字符开始 | |
print_match('re.match', re.match(r1, s)) | |
print_match('re.search', re.search(r2, s)) | |
def test2(): | |
s = 'abbabbabbabba' | |
#默认是贪婪匹配,在*,?,{}后面加上一个问号,变成非贪婪匹配 | |
print_match('greed\t', re.search('a(.*)a', s)) | |
print_match('non-greed', re.search('a(.*?)a', s)) | |
def test3(): | |
s = 'abbabbabbabba' | |
#{a,b}最少匹配a次,最多匹配b次,默认贪婪,加上问号则变成非贪婪匹配 | |
print_match('count\t', re.search('a(bba){1,2}', s)) | |
print_match('non-greed', re.search('a(bba){1,2}?', s)) | |
def test4(): | |
s = 'abbabbabbabba' | |
#中括号表示可以使用其中的任意一个字符 | |
print_match('[]\t', re.search('a[ab]*', s)) | |
#单竖线表示两边的都可以匹配,两边可以不只是一个字节 | |
print_match('|\t', re.search('(a|b)*', s)) | |
def test5(): | |
s = 'abbabbabbabba' | |
#圆括号表示提取这段内容作为一个小组,以后可以用\1, \2等来引用 | |
m = re.search('a(b)(b.b)(.*)ab', s) | |
print_match('()\t', m) | |
#group(n)是第n个圆括号中的内容,groups()列出所有小组,但是不包括group(0) | |
print '\tm.group(1):', m.group(1) | |
print '\tm.groups:', m.groups() | |
s = 'abcdremove_meefg' | |
m = re.search('remove_me', s) | |
#matchobject类有start和end两个方法,可以返回某个组的起始位置和结束位置 | |
#这里演示的是靠这两个位置和切片函数,实现删除字符串的部分内容 | |
s = s[:m.start()] + s[m.end():] | |
print 'start()/end()\t', s | |
s = 'abcdremove_meefg' | |
#start和end后面可以加上参数,用于指定某个小组 | |
#默认不写的话就是0,表示整个匹配 | |
m = re.search('d(remove_me)e', s) | |
s = s[:m.start(1)] + s[m.end(1):] | |
print 'start(1)/end(1)\t', s | |
def test6(): | |
#(?)是一组特殊的用法,分别举例如下 | |
s = 'aA' | |
#问号后面加上几个特殊的字母,可以对整个匹配进行一些设置 | |
#在这里设置的优点是,只要告诉别人这个pattern,就知道设置了 | |
#后面可以跟的字符有‘iLmsux’,可以任意组合,注意大小写,常用的几个介绍如下 | |
#i,忽略大小写 | |
#m,^可以在多行文本中匹配每行开头,默认情况下只能匹配字符串开头,同理,$可以匹配每行末尾 | |
#s,'.'可以匹配换行符,默认是只能匹配除了换行符以外的任意字符 | |
print_match('(?i)\t', re.search('(?i)aa', s)) | |
s = 'a\nAa' | |
print_match('(?mi)\t', re.search('(?mi)aa', s)) | |
print_match('(?mis)\t', re.search('(?mis)....', s)) | |
#(?:)和一对圆括号差不多,唯一不同是里面的内容不会记录到group里面 | |
s = 'abcdef' | |
m = re.search('(?:a)(..)', s) | |
print_match('(?:)\t', m) | |
print '\tgroups:', m.groups() | |
print '\tgroupdict:', m.groupdict() | |
#(?P<id>)可以给一个group起名字,后面可以用名字引用这个group,增加可读性 | |
m = re.search('(?P<test>a)(?P<test2>..)', s) | |
print_match('(?P)\t', m) | |
print '\tgroups:', m.groups() | |
print '\tgroupdict:', m.groupdict() | |
print '\tgroup(test):', m.group('test') | |
print '\tgroup(test2):', m.group('test2') | |
#(?#)就是注释,会被忽略 | |
#(?P=id)可以引用前面定义好的组名 | |
s = 'abcdefabcdef' | |
m = re.search('(?#commnt)(?P<a>...).*(?P=a)', s) | |
print_match('(?P=name)', m) | |
print '\tgroups:', m.groups() | |
print '\tgroupdict:', m.groupdict() | |
#下面四个都是零长度匹配,前两个是前向匹配,后两个是后向匹配 | |
#(?=)要求后面必须要有指定的内容,前面的内容才有效 | |
#(?!)要求后面必须没有指定的内容,前面的内容才有效 | |
#(?<=)要求前面必须是指定内容,后面的内容才有效 | |
#(?<!)要求前面必须不是指定内容,后面的内容才有效 | |
#反正比较难以用语言解释,看看下面四个语句运行的结果,应该能帮助理解 | |
s = 'abcdeabbbb' | |
print_match('(?=)\t', re.search('ab(?=cde)...', s)) | |
print_match('(?!)\t', re.search('ab(?!cde)...', s)) | |
#注意,下面两个要求括号中的匹配长度是固定的,比如不能有*或{2, 3}这种匹配不定长的语法 | |
print_match('(?<=)\t', re.search('.(?<=a)b', s)) | |
print_match('(?<!)\t', re.search('.(?<!a)b', s)) | |
#这是一个很特别的语法,和C的?:差不多,判断前面一个组是否匹配上了,如果匹配上,那么这段内容等效于y,否则等效于n(y和n可以是任意pattern),一般用法就是用来匹配括号,比如下面的语句,同样的语句,可以匹配'abc'或'[abc]',但是不能匹配'[abc' | |
s = 'abc' | |
print_match('(?(id)y|n)', re.search('(\[)?abc(?(1)\])', s)) | |
s = '[abc]' | |
print_match('(?(id)y|n)', re.search('(\[)?abc(?(1)\])', s)) | |
def test7(): | |
s = 'abcdef' | |
#re.compile返回一个RegexObject,如果某个pattern要经常使用,这么弄可以提高效率,但是如果只是少量的使用,不会有明显区别 | |
e = re.compile('abcde') | |
print_match('re.compile', e.search(s)) | |
def test8(): | |
#下面是re.sub()函数的用法,这个函数用于实现替换,还有一个subn,功能和sub一样,但是返回值是一个tuple,多了一个返回值,表示总共替换了几次 | |
#如果要实现把a换成b,如下 | |
print 're.sub()', re.sub('a', 'b', 'ababa') | |
#可以限制只替换n次 | |
print 're.sub()', re.sub('a', 'b', 'aaaaa', 3) | |
#第二个参数可以很丰富多彩,即可以是一个字符串,也可以是一个函数名,也可以是一个lamda表达式 | |
#另外,还可以通过\1来引用第一个子匹配,\g<id>引用(?P<id>)定义的子匹配,\g<1>和\1等效,但是\g<2>0可以表示第二个子匹配后面加上0,这个用\20就无法表示了 | |
print 're.sub()', re.sub('(?P<aaa>a)bcd(e)', r'\2\g<aaa>\1', 'abcde') | |
#如果第二个参数是函数名或者lamda表达式,表示用这个函数的返回值,来替换匹配的内容 | |
print 're.sub()', re.sub('a', lambda m: 'b', 'abababa') | |
#要注意的就是,这个函数是有一个参数的,类型是matchobject,就是整个匹配的信息 | |
print 're.sub()', re.sub('a', lambda m: '(' + str(m.start()) + ',' + str(m.end()) + ')', 'babbbbab') | |
def test9(): | |
s = 'abcdefgabcdefgabcdefg' | |
#re.findall用于查找所有的匹配(re.search只匹配一次,后面的就忽略了) | |
#返回值是一个list,元素可能是字符串,也可能是tuple,取决于有多少个子匹配 | |
#如果没有子匹配,list中是每次匹配的整个内容 | |
print 're.findall', re.findall('abc', s) | |
#如果有一个子匹配,list中是这个子匹配的内容 | |
#如果有多个子匹配,list中是这些子匹配构成的tuple | |
print 're.findall', re.findall('(a)b(c)', s) | |
#如果需要得到多次匹配的MatchObject,则需要用re.finditer,他的返回值就是MatchObject的List | |
for m in re.finditer('abc', s): | |
print_match('re.finditer()', m) | |
#另外还有一些常用的,比如 | |
#\A 匹配字符串开头 \Z匹配字符串结尾 | |
#\d 匹配数字 \D 匹配所有非数字字符 | |
#\s 匹配空白字符 \S 匹配非空白字符 | |
#\w 匹配数字字母下划线 \W 反之 | |
if __name__ == '__main__': | |
test1() | |
test2() | |
test3() | |
test4() | |
test5() | |
test6() | |
test7() | |
test8() | |
test9() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment