Python基础知识——正则表达式
正则表达式
什么是正则?
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。
或者说:正则就是用来描述一类事物的规则。
(在Python中)它内嵌在Python中,并通过 re 模块实现。
正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
正则表达式是一种小型的、高度专业化的编程语言。
正则所处理的对象就是字符串。
对于一般的普通字符的匹配,用字符串的内置方法就能完成的,推荐用内置方法,对于其不能完成的,再用正则。
元字符
. : 匹配除换行符外任意的单个字符
>>> re.findall('aa..', 'aa') #正则匹配的字符以列表形式返回 [] >>> re.findall('aa..', 'bbaacc') #每个 . 代表一个字符 ['aacc'] >>> re.findall('aa..', '..aa..') # . 匹配任意字符, 包括 . ['aa..'] >>> re.findall('..', '\n\n') # . 不能匹配\n [] >>> re.findall('..', 'a\na\t') # . 可以匹配\t ['a\t'] >>> re.findall('..', '\n\n', flags = re.DOTALL) #flags设置为DOTALL时, . 可以匹配换行符 ['\n\n']
^: 从字符串开头开始匹配
>>> re.findall('^..', 'abcdefg12345') ['ab'] >>> re.findall('^12', '1312121212') []
$ :从字符串末尾开始匹配
>>> re.findall('..$', 'abcdefg12345') ['45'] >>> re.findall('12$', '1212121213') []
* :匹配前一个字符或片段的0个、1个或多个重复的字符或片段
>>> re.findall('a*', 'bbbbbbbb') #每检测到一个b都返回一个0a ['', '', '', '', '', '', '', '', ''] >>> re.findall('a*', 'aaaaabaaaaa') #字符串结尾的结束字符也在检测范围内 ['aaaaa', '', 'aaaaa', ''] >>> re.findall('a*', 'ababababab') #同理,*字符可以匹配零个字符需要特殊处理 ['a', '', 'a', '', 'a', '', 'a', '', 'a', '', ''] >>> re.findall('abc*', 'abcccccc') #正常的贪婪匹配 ['abcccccc'] >>> re.findall('abc*', 'abcabcabc') #每遇到一个就返回一个 ['abc', 'abc', 'abc']
+ :匹配前一个字符或片段的1个或多个重复的字符或片段
#与上述 * 的使用做对比 >>> re.findall('a+', 'bbbbbbbb') [] >>> re.findall('a+', 'aaaaabaaaaa') ['aaaaa', 'aaaaa'] >>> re.findall('a+', 'ababababab') ['a', 'a', 'a', 'a', 'a'] >>> re.findall('abc+', 'abcccccc') #同样是贪婪匹配 ['abcccccc'] >>> re.findall('abc+', 'abcabcabc') ['abc', 'abc', 'abc']
?: 匹配0个或者1个由前面正则所定义的片段
#同上对比 >>> re.findall('a?', 'bbbbbbbb') #同样需要处理为零个的情况 ['', '', '', '', '', '', '', '', ''] >>> re.findall('a?', 'aaaaabaaaaa') ['a', 'a', 'a', 'a', 'a', '', 'a', 'a', 'a', 'a', 'a', ''] #0或1个 >>> re.findall('a?', 'ababababab') ['a', '', 'a', '', 'a', '', 'a', '', 'a', '', ''] #包括字符串结尾的\0字符 >>> re.findall('abc?', 'abcccccc') #依然是贪婪匹配,匹配能匹配的最大值 ['abc'] >>> re.findall('abc?', 'abcabcabc') ['abc', 'abc', 'abc'] #在正则式末尾加上?,则变为惰性匹配,能不匹配就不匹配 >>> re.findall('a*?', 'aaaaabaaaaa') ['', '', '', '', '', '', '', '', '', '', '', ''] >>> re.findall('a*?', 'bbbbbbbb') ['', '', '', '', '', '', '', '', ''] >>> re.findall('a*?', 'aaaaabaaaaa') ['', '', '', '', '', '', '', '', '', '', '', ''] >>> re.findall('abc*?', 'abcccccc') ['ab'] >>> re.findall('abc*?', 'abcabcabc') ['ab', 'ab', 'ab']
{}: 决定该符号前正则式的重复次数
>>> re.findall('a{3}', 'aaaaaaaaaaaaaa') #只重复3次 ['aaa', 'aaa', 'aaa', 'aaa'] >>> re.findall('a{1,3}', 'aaaaaaaaaaaaaa') #重复1-3次,优先贪婪匹配 ['aaa', 'aaa', 'aaa', 'aaa', 'aa'] >>> re.findall('a{1,20}', 'aaaaaaaaaaaaaa') #没有最大次数的情况下,逐次递减 ['aaaaaaaaaaaaaa'] >>> re.findall('a{20}', 'aaaaaaaaaaaaaa') #次数确定,匹配不到则返回空 []
[ ]: 用来表示一组字符
>>> re.findall('[abc]+', 'abcabcabc') #[]内的内容表示一组选择列表 ['abcabcabc'] >>> re.findall('[abc]+', 'ababab') #贪婪匹配,有多少匹配多少 ['ababab'] >>> re.findall('a[bc]d', 'abcd') #[]的一次匹配对应一个字符 [] >>> re.findall('a[bc]d', 'abdacd') #[]内的所有内容,每个字符按或关系处理 ['abd', 'acd'] >>> re.findall('[abc]{1,3}', 'aabbcc') #{}表示匹配的次数范围 ['aab', 'bcc'] >>> re.findall('[abc]{4}', 'aabbcc') #表示匹配的准确次数 ['aabb'] >>> re.findall('[abc]', 'aabbcc') #[]的每次匹配对应一个字符 ['a', 'a', 'b', 'b', 'c', 'c'] >>> re.findall('[\d]', 'ad13') #[]中\依然有元字符的作用 ['1', '3'] >>> re.findall('[*.+?{}$]', '*.+?{}$') #其余字符全部作为普通字符进行匹配 ['*', '.', '+', '?', '{', '}', '$'] >>> re.findall('[^*.+?{}$]', '*.+?{}$123') #^为取反,匹配到[]内所有不包含的内容 ['1', '2', '3'] re.findall('[1-9]', '123456') #1-9表示范围[1, 9], 仅在[]中有该作用 ['1', '2', '3', '4', '5', '6']
a | b :匹配a和b中的任意一个
>>> re.findall('1|2', '12345123112') ['1', '2', '1', '2', '1', '1', '2'] >>> re.findall('a.|2', 'aba2aaaa222a2') ['ab', 'a2', 'aa', 'aa', '2', '2', '2', 'a2'] >>> re.findall('a.|2.', 'abvva22') ['ab', 'a2']
():将括号内作为一个整体进行匹配,匹配后只返回括号内的值
>>> re.findall('123(aaa)456', '123a456') #括号内作为整体,不满足匹配 [] >>> re.findall('123(aaa)456', '123aaaaaa456') #同上 [] >>> re.findall('123(aaa)456', '123aaa456') #只返回括号内的内容 ['aaa'] >>> re.findall('[123(aaa)456]', '123aaa456') #()在[]中为普通字符 ['1', '2', '3', 'a', 'a', 'a', '4', '5', '6']
\ : 转义符
功能:
反斜杠后边跟元字符去除特殊功能
反斜杠后边跟普通字符实现特殊功能
转义符实现的特殊功能(可以在[]中使用):
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
\A 从字符串开始匹配
\Z 从字符串结束开始匹配,如果存在换行,匹配到换行符之前
\z 从字符串结束开始匹配
\G 匹配最后匹配完成的位置
\n 匹配换行符
\t 匹配制表符
>>> re.findall('\.\+\$\^\*', '.+$^*') ['.+$^*'] >>> re.findall('\(a\)', '(a)') ['(a)'] 如果要匹配出\: >>> re.findall(r'c\\l', 'aabc\lcaa') #r代表raw,表示该字符串不会被转义处理 ['c\\l'] >>> re.findall('c\\\\l', 'aabc\lcaa') ['c\\l'] #re模块会对\进行转义,而python解释器也会对\进行转义,所以输入时为四个\,输出时为两个\ 另外: >>> re.findall('\bblow', 'blow') [] >>> re.findall(r'\bblow', 'blow') ['blow']
re模块的方法:
re.findall(pattern, string, flags=0):返回所有满足匹配条件的结果,放在列表里,找到一个匹配结果后,从当前位置开始再次进行匹配。
re.search(pattern, string, flags=0):函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的match对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
re.match(pattern, string, flags=0):同search,不过仅在字符串开始处进行匹配
re.split(pattern, string, maxsplit=0, flags=0):以匹配到的字符当做列表分隔符
re.sub(pattern, replace, string, count=0, flags=0):匹配字符串并替换,count代表替换的次数,默认全部替换
re.subn(pattern, replace, string, count=0, flags=0):同sub返回值返回一个元组,包括替换后的字符串和替换的次数
re.compile(pattern, flags=0):返回一个pattern对象,包含了定义时的匹配规则,可以直接通过该匹配规则调用各种方法
re.finditer(pattern, string, flags=0):同findall,返回一个迭代器对象
#patter即为匹配规则,用正则表达式表示
# ===========================re模块提供的方法介绍=========================== import re #1 print(re.findall('e','alex make love') ) #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里 #2 print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 #3 print(re.match('e','alex make love')) #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match #4 print(re.split('[ab]','abcd')) #['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割 #5 print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有 print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数 #6 obj=re.compile('\d{2}') print(obj.search('abc123eeee').group()) #12 print(obj.findall('abc123eeee')) #['12'],重用了obj
import re print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")) print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").group()) print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").groupdict()) print(re.search(r"<(\w+)>\w+</(\w+)>","<h1>hello</h1>").group()) print(re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>").group()) 运行结果: C:\Users\Clingyu\Desktop>python 1.py ['h1'] <h1>hello</h1> {'tag_name': 'h1'} <h1>hello</h1> <h1>hello</h1>
关于正则更详细的介绍:
http://www.cnblogs.com/chengmo/archive/2010/10/10/1847287.html
简单匹配模式
最常规匹配:
import re content='Hello 123 456 World_This is a Regex Demo' res=re.match('Hello\s\d\d\d\s\d{3}\s\w{10}.*Demo',content) print(res) print(res.group()) print(res.span()) 运行结果: C:\Users\Clingyu\Desktop>python 1.py <_sre.SRE_Match object; span=(0, 40), match='Hello 123 456 World_This is a Regex Demo'> Hello 123 456 World_This is a Regex Demo (0, 40)
泛匹配:
import re content='Hello 123 456 World_This is a Regex Demo' res=re.match('^Hello.*Demo',content) print(res.group()) 运行结果: C:\Users\Clingyu\Desktop>python 1.py Hello 123 456 World_This is a Regex Demo 目标匹配: import re content='Hello 123 456 World_This is a Regex Demo' res=re.match('^Hello\s(\d+)\s(\d+)\s.*Demo',content) print(res.group()) #取所有匹配的内容 print(res.group(1)) #取匹配的第一个括号内的内容 print(res.group(2)) #取匹配的第二个括号内的内容 运行结果: C:\Users\Clingyu\Desktop>python 1.py Hello 123 456 World_This is a Regex Demo 123 456
贪婪匹配:
.*代表匹配尽可能多的字符 import re content='Hello 123 456 World_This is a Regex Demo' res=re.match('^He.*(\d+).*Demo$',content) print(res.group(1)) #只打印6,因为.*会尽可能多的匹配,然后后面需要至少一个数字 运行结果: C:\Users\Clingyu\Desktop>python 1.py 6
非贪婪匹配:
?匹配尽可能少的字符 import re content='Hello 123 456 World_This is a Regex Demo' res=re.match('^He.*?(\d+).*Demo$',content) print(res.group(1)) 运行结果: C:\Users\Clingyu\Desktop>python 1.py 123
匹配模式不能匹配换行符的解决方式:
import re content='''Hello 123456 World_This is a Regex Demo ''' res=re.match('He.*?(\d+).*?Demo$',content) print(res) #输出None res=re.match('He.*?(\d+).*?Demo$',content,re.S) #re.S让.可以匹配换行符 print(res) print(res.group(1)) 运行结果: C:\Users\Clingyu\Desktop>python 1.py None <_sre.SRE_Match object; span=(0, 39), match='Hello 123456 World_This\nis a Regex Demo'> 123456
总结:
- 尽量精简
- 尽量使用泛匹配模式 : .*
- 尽量使用非贪婪模式 : .*?
- 使用括号得到匹配目标 : 用group(n)去取得结果
- 有换行符就用re.S : 修改模式

浙公网安备 33010602011771号