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 : 修改模式
posted @ 2018-03-07 09:30  Clingyu  阅读(124)  评论(0)    收藏  举报