Python 正则表达模块详解
正则表达式(Regluar Expressions)又称规则表达式,这个概念最初是由Unix中的工具软件(如sed 和 grep)普及开的,正则表达式在代码中常简写为RES,它本质上是一个小巧的、高度专用的编程语言,许多程序设计语言都支持通过正则表达式进行字符串操作,通俗的来讲,正则就是用一些具有特殊含义的符号组合到一起来描述字符或者字符串的方法,正则模块内嵌在Python中,并通过re模块实现,正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行.
## 通用字符匹配
语法 | 通配符匹配作用解析 |
---|---|
. | 默认匹配除\n 之外的任意一个字符,若指定flag=DOTALL则匹配任意字符,包括换行 |
\ | 转义字符,通常情况下使后一个字符改变原来的意思,也就是脱意字符 |
[x..y] | 字符集(字符类),此参数用来指定一个字符查找范围 |
\A | 只从字符开头匹配,如果使用·re.search("\Aabc","alexabc") 则匹配不到的结果 |
\Z | 只匹配字符结尾,匹配字符结尾是指定数据的字符串,同$ 符号作用相同 |
\d | 匹配数字,范围是[0-9] ,匹配0-9中的任意数字 |
\D | 匹配非数字,范围是[^\d] ,匹配除了数字以外的其他字符 |
\w | 匹配数字或字符,匹配范围[A-Za-z0-9] |
\W | 匹配非字符或数字,匹配范围非[A-Za-z0-9] |
s | 匹配空白字符,例如匹配re.search("\s+","ab\tc1\n3").group() 结果为'\t' |
正则符号(.
): 匹配除了换行符以外的任意一个字符,一个点只代表一个字符.
>>> import re
>>> re.search("he.o","helo hello helllo hellllo").group()
'helo'
>>> re.search("he...o","helo hello helllo hellllo").group()
'helllo'
>>> re.findall("he.o","helo heao hello helllo hellllo")
['helo', 'heao']
正则符号(\
): 匹配数据时,需要转义的使用会用到,这个转义字符.
>>> re.search("..\\t","hello\t lyshark\n").group()
'lo\t'
>>> re.search("\\t","hello\t lyshark\n").group()
'\t'
>>> re.search("\t","hello\t lyshark\n").group()
'\t'
>>> re.search(r"\\","hello\\lyshark").group()
'\\'
正则符号([]
): 匹配查找指定的数据范围,通常使用[0-9] [a-z] [A-Z]
这几个匹配格式.
>>> re.search("[0-9]","hello 1,2,3,4,5").group()
'1'
>>> re.findall("[0-9]","hello 1,2,3,4,5")
['1', '2', '3', '4', '5']
>>> re.search("[^0-9]","hello 1,2,3,4,5").group()
'h'
>>> re.search("[a-z]","hello 1,2,3,4,5").group()
'h'
>>> re.search("^[a-z]","hello 1,2,3,4,5").group()
'h'
>>> re.search("[^a-z]","hello 1,2,3,4,5").group()
' '
>>> re.search("[^A-Z]","hello 1,2,3,4,5").group()
'h'
## 通用边界匹配
语法 | 通配符匹配作用解析 |
---|---|
. | 默认匹配除\n 之外的任意一个字符,若指定flag=DOTALL 则匹配任意字符,包括换行 |
^ | 匹配以指定字符开头的数据,search(r"^a","\nabc\neee",flags=re.MULTILINE) |
$ | 匹配以指定字符结尾的数据,search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group() |
* | 匹配* 号前的字符0次或多次,findall("ab*","cabb3abcbbac") 结果['abb', 'ab', 'a'] |
+ | 匹配前一个字符1次或多次,findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb'] |
? | 匹配前一个字符1次或0次,findall("ab?","ab,a,abc,abcde") 结果['ab', 'a', 'ab', 'ab'] |
竖线 | 匹配选择竖线左边或右边的字符,search("abc竖线ABC","ABCBabcCD").group() 结果['ABC'] |
{m} | 匹配前一个字符出现过m次,search("hello{2}","hello,helloo).group() 结果['helloo'] |
{n,m} | 匹配前一个字符,最少出现过n次,最多出现过m次 |
(?P...) | 分组匹配,search("(?P[a-zA-Z]+)(?P[0-9]+)","lyshark22").groupdict("temp") |
正则符号(^$
): ^
匹配指定字符开头的数据,$
匹配指定字符结尾的数字.
>>> re.search(r"^h","hello world")
<re.Match object; span=(0, 1), match='h'>
>>> re.search(r"^h","hello world").group()
'h'
>>> re.search(r"world$","hello\nworld")
<re.Match object; span=(6, 11), match='world'>
>>> re.search(r"world$","hello\nworld").group()
'world'
正则符号(*
): 匹配星号前面的字符出现0次,或任意多次.
>>> re.findall("ab*","abccba23acbcabb")
['ab', 'a', 'a', 'abb']
正则符号(+
): 匹配加号前面的字符出现过1次,或任意多次,至少出现一次.
>>> re.findall("ab+","abccba23acbcabb")
['ab', 'abb']
正则符号(?
): 匹配前一个字符出现过1次,或0次,允许出现0次.
>>> re.findall("ab?","ab,abc,abb,abcd,a,acd,abc")
['ab', 'ab', 'ab', 'ab', 'a', 'a', 'ab']
>>> re.findall("ab?","ab,a,abc,abcde")
['ab', 'a', 'ab', 'ab']
正则符号(|
): 匹配选择竖线左边,或者右边的任意一种情况.
>>> re.search("abc|ABC","ABCBabcCD").group()
'ABC'
>>> re.findall("abc|ABC","ABCBabcCD")
['ABC', 'abc']
正则符号(x{m}
): 匹配前一个字符x,出现过m次的行.
>>> re.search("hello{2}","hello,helloo,hellooo,helloooo").group()
'helloo'
>>> re.search("hello{3}","hello,helloo,hellooo,helloooo").group()
'hellooo'
正则符号(x{n,m}
): 匹配前一个字符x,最少出现过n次,最多出现过m次.
>>> re.search("hello{1,2}","hello,helloo,hellooo,helloooo").group()
'hello'
>>> re.findall("hello{1,2}","hello,helloo,hellooo,helloooo")
['hello', 'helloo', 'helloo', 'helloo']
正则符号((?P<name>...)
): 匹配相关条件并自动分组,并打印出结果,其中?P<..>
是固定写法,后面紧跟正则规则.
>>> number = "371481199306143242"
>>> re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})",number).groupdict()
{'province': '3714', 'city': '81', 'birthday': '1993'}
>>> re.search("(?P<name>[a-zA-Z]+)(?P<age>[0-9]+)","lyshark22").groupdict("temp")
{'name': 'lyshark', 'age': '22'}
## 常用匹配函数
函数与方法名 | 通配符匹配作用解析 |
---|---|
regex.match | 从字符串开头位置匹配查找,如果0个或多个字符被匹配则返回相应的匹配对象,如果不匹配则返回None. |
regex.search | 扫描整个字符串,查找正则匹配到的字串中第一次出现的位置,并返回相应的匹配对象,如果匹配失败则返回None. |
regex.findall | 搜索字符串中与正则表达式匹配的所有子串,也就是查找字符串中所有的匹配结果,并且以列表的形式返回数据. |
regex.sub | 字符串的替换,简单来说就是替换字符串中与正则表达式匹配的指定数量的子串,最后返回替换修改后的字符串. |
regex.split | 以正则表达式匹配的字符串作为分隔符,对一个字符串进行分割,以列表形式返回分割后的各个字符串. |
match.expand | 通过得到的匹配对象来构造并返回一个新的字符串,未被匹配到的分组将被替换为一个空字符串. |
match.group | 返回一个或多个指定捕获组所匹配到的内容,如果只有1个参数则返回单独的字符串,多参数返回元组. |
match.groups | 返回一个包含所有分组所匹配内容的元组,如果某个分组没有匹配到内容,则取defalult所指定的值. |
match.groupdict | 返回一个包含所有命名分组名称及其所匹配内容的字典对象,如果某个分组没有匹配到内容则取默认值. |
regex.match(): 从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None.
match(pattern,string,flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式
#------------------------------------------------
# 未分组情况下.
>>> origin = "hello alex bcd abcd lge acd 19"
>>>
>>> ret = re.match("h\w+",origin)
>>> print(ret.group()) #获取匹配到的所有结果
>>> print(ret.groups()) #获取模型中匹配到的分组结果
>>> print(ret.groupdict()) #获取模型中匹配到的分组结果
#------------------------------------------------
# 有分组情况下. 提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
>>> ret = re.match("h(\w+).*(?P<name>\d)$",origin)
>>> print(r.group()) #获取匹配到的所有结果
>>> print(r.groups()) #获取模型中匹配到的分组结果
>>> print(r.groupdict()) #获取模型中匹配到的分组中所有执行了key的组
regex.search(): 搜索整个字符串去匹配第一个符合条件的数据,未匹配成功返回None.
>>> origin = "hello alex bcd abcd lge acd 19"
>>>
>>> re.search("^h\w+",origin).group() #匹配开头是h的后面是任意字符的
'hello'
>>> re.search("a\w+",origin).group() #匹配a开头后面是任意字符的
'alex'
>>> re.search("(?P<name>a\w+)",origin).groupdict()
{'name': 'alex'} #分组匹配并过滤出alex
>>> re.search("(?P<姓名>[a-zA-Z]+)(?P<年龄>[0-9]+)","lyshark22").groupdict()
{'姓名': 'lyshark', '年龄': '22'} #匹配字符串,并分组打印出结果
regex.findall(): 获取非重复的匹配列表,如果有一个组则以列表形式返回,且每一个匹配均是字符串,空的匹配也会包含在结果中.
>>> origin = "hello alex bcd abcd lge acd 19"
>>> re.findall("al\w+",origin)
['alex'] #匹配到单个结果,则以单列表返回
>>> re.findall("a\w+",origin)
['alex', 'abcd', 'acd'] #匹配到多个结果,则以列表形式返回
regex.sub(): 先匹配查找结果,然后进行字串的替换,也就是替换匹配成功的指定位置字符串.
sub(pattern,repl,string,count=0,flags=0)
# pattern: 正则模型
# repl : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count : 指定匹配个数
# flags : 匹配模式
>>> origin = "hello alex bcd abcd lge acd 19"
>>> re.sub("a[a-z]+","999999",origin,1) #匹配以a开头则字串,并替换成9999,替换1次
'hello 999999 bcd abcd lge acd 19'
>>> re.sub("a[a-z]+","999999",origin,2) #匹配以a开头则字串,并替换成9999,替换2次
'hello 999999 bcd 999999 lge acd 19'
regex.split(): 字符串切割函数,用来实现对指定字符串的分割工作,根据正则匹配分割字符串.
split(pattern,string,maxsplit=0,flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags : 匹配模式
>>> origin = "hello alex bcd abcd lge acd 19"
>>> re.split("alex",origin,1) #无分组切割
['hello ', ' bcd abcd lge acd 19']
>>> re.split("(alex)",origin,1) #有分组,以alex最为分隔符,切割字符串
['hello ', 'alex', ' bcd abcd lge acd 19']
常用匹配: 下面举几个小例子,分别用来匹配IP地址,手机号,和邮箱地址.
IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
手机号:
^1[3|4|5|8][0-9]\d{8}$
邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+
## Flage 标识位
re.DOTALL
# 正则表达式默认以单行开始匹配的
import re
def re_pattern_syntax():
# .表示任意单一字符
# *表示前一个字符出现>=0次
# re.DOTALL就可以匹配换行符\n,默认是以行来匹配的
print(re.match(r'.*', 'abc\nedf').group())
print('*' * 80)
print(re.match(r'.*', 'abc\nedf',re.DOTALL).group())
if __name__ == '__main__':
re_pattern_syntax()
re.MULTILINE
# 正则表达式默认以单行开始匹配的
import re
def re_pattern_syntax1():
# ^表示字符串开头(单行)
# re.MULTILINE多行匹配字符串开头
print(re.findall(r'^abc', 'abc\nedf'))
print('*' * 80)
print(re.findall(r'^abc', 'abc\nabc',re.MULTILINE))
def re_pattern_syntax2():
# $表示字符串结尾
# re.MULTILINE表示行的结束
print(re.findall(r'abc\d$', 'abc1\nabc2'))
print('*' * 80)
print(re.findall(r'abc\d$', 'abc1\nabc2',re.MULTILINE))
if __name__ == '__main__':
re_pattern_syntax1()
re_pattern_syntax2()
?非贪婪模式
import re
def re_pattern_syntax4():
# greedy贪婪/non-greedy非贪婪,默认的是贪婪的匹配
s = '<H1>title</H1>'
print(re.match(r'<.+>', s).group()) #贪婪模式会匹配尽量多的匹配
print(re.match(r'<.+?>', s).group()) #非贪婪模式匹配尽量少的匹配
print(re.match(r'<(.+)>', s).group(1))
print(re.match(r'<(.+?)>', s).group(1))
def re_pattern_syntax5():
# {m}/{m,}/{m,n}
print(re.match(r'ab{2,4}', 'abbbbbbb').group()) #贪婪模式尽量匹配多
print(re.match(r'ab{2,4}?', 'abbbbbbb').group()) #非贪婪模式尽量匹配少
print('*' * 80)
if __name__ == '__main__':
re_pattern_syntax4()
re_pattern_syntax5()
re.I/re.IGNORECASE
import re
def re_pattern_flags():
# re.I/re.IGNORECASE
print(re.match(r'(Name)\s*:\s*(\w+)','NAME : Joey',re.IGNORECASE).groups())
print('*' * 80)
if __name__ == '__main__':
re_pattern_syntax_meta_char()
re.VERBOSE
import re
def re_pattern_flags1():
# re.VERBOSE此标识位可以添加注释/re.compile
s = 'the number is 20.5'
r = re.compile(r'''
\d+ # 整数部分
\.? # 小数点,可能包含也可能不包含
\d* # 小数部分,可选
''',re.VERBOSE)
print(re.search(r,s).group())
print(r.search(s).group())
print('*' * 80)
if __name__ == '__main__':
re_pattern_syntax_meta_char1()
## 有无分组比较
re.mach()
# 无分组
r = re.match("h\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果
# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
r = re.match("h(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
re.search()
# 无分组
r = re.search("a\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果
# 有分组
r = re.search("a(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
re.findall()
# 无分组
r = re.findall("a\w+",origin)
print(r)
# 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r)
re.split()
# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r)
# 有分组
origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
r2 = re.split("(al(ex))", origin, 1)
print(r2)
常用例子
import re
print(re.findall(r'(\d+)-([a-z])','34324-dfsdfs777-hhh')) # [('34324', 'd'), ('777', 'h')]
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(0)) # 34324-d 返回整体
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(1)) # 34324 获取第一个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(2)) # d 获取第二个组
print(re.search(r'(\d+)-([a-z])','34324-dfsdfs777-hhh').group(3)) # IndexError: no such group
print(re.search(r"(jason)kk\1","xjasonkkjason").group()) #\1表示应用编号为1的组 jasonkkjason
print(re.search(r'(\d)gg\1','2j333gg3jjj8').group()) # 3gg3 \1表示使用第一个组\d
# 下面的返回None 为什么是空?而匹配不到3gg7,因为\1的不仅表示第一组,而且匹配到的内容也要和第一组匹配到的内容相同,第一组匹配到3,第二组匹配到7 不相同所以返回空
print(re.search(r'(\d)gg\1','2j333gg7jjj8'))
print(re.search(r'(?P<first>\d)abc(?P=first)','1abc1')) # 1abc1 声明一个组名,使用祖名引用一个组
r=re.match('(?P<n1>h)(?P<n2>\w+)','hello,hi,help') # 组名的另外一种用法
print(r.group()) # hello 返回匹配到的值
print(r.groups()) # ('h', 'ello')返回匹配到的分组
print(r.groupdict()) # {'n2': 'ello', 'n1': 'h'} 返回分组的结果,并且和相应的组名组成一个字典
# 分组是从已经匹配到的里面去取值
origin ="hello alex,acd,alex"
print(re.findall(r'(a)(\w+)(x)',origin)) # [('a', 'le', 'x'), ('a', 'le', 'x')]
print(re.findall(r'a\w+',origin)) # ['alex', 'acd', 'alex']
print(re.findall(r'a(\w+)',origin)) # ['lex', 'cd', 'lex']
print(re.findall(r'(a\w+)',origin)) # ['alex', 'acd', 'alex']
print(re.findall(r'(a)(\w+(e))(x)',origin)) # [('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')]
r=re.finditer(r'(a)(\w+(e))(?P<name>x)',origin)
for i in r :
print(i,i.group(),i.groupdict())
'''
[('a', 'le', 'e', 'x'), ('a', 'le', 'e', 'x')]
<_sre.SRE_Match object; span=(6, 10), match='alex'> alex {'name': 'x'}
<_sre.SRE_Match object; span=(15, 19), match='alex'> alex {'name': 'x'}
'''
print(re.findall('(\w)*','alex')) # 匹配到了alex、但是4次只取最后一次即 x 真实括号只有1个
print(re.findall(r'(\w)(\w)(\w)(\w)','alex')) # [('a', 'l', 'e', 'x')] 括号出现了4次,所以4个值都取到了
origin='hello alex sss hhh kkk'
print(re.split(r'a(\w+)',origin)) # ['hello ', 'lex', ' sss hhh kkk']
print(re.split(r'a\w+',origin)) # ['hello ', ' sss hhh kkk']
Python 正则表达模块详解的更多相关文章
- Python中time模块详解
Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...
- python之OS模块详解
python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...
- python之sys模块详解
python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
- Python的logging模块详解
Python的logging模块详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.日志级别 日志级别指的是产生的日志的事件的严重程度. 设置一个级别后,严重程度 ...
- python中常用模块详解二
log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...
- Python中time模块详解(转)
在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. 在开始之前,首先要说明这几点: ...
- python中socket模块详解
socket模块简介 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket.socket通常被叫做"套接字",用于描述IP地址和端口,是一个通信 ...
- python的re模块详解
一.正则表达式的特殊字符介绍 正则表达式 ^ 匹配行首 $ 匹配行尾 . 任意单个字符 [] 匹配包含在中括号中的任意字符 [^] 匹配包含在中括号中的字符之外的字符 [-] 匹配指定范围的任意单个字 ...
随机推荐
- Babel7知识梳理
Babel7 知识梳理 对 Babel 的配置项的作用不那么了解,是否会影响日常开发呢?老实说,大多情况下没有特别大的影响(毕竟有搜索引擎). 不过呢,还是想更进一步了解下,于是最近认真阅读了 Bab ...
- CF1197C
CF1197C 题意: 有一个递增的数列,把它分成k段,找到这样的分段方法,即每段最大值减最小值的和最小 解法: 分成k段,即要加k-1个隔断,这k-1个隔断,能隔开差值最大的几个,那最后得到分隔后的 ...
- JAVA - IO - IO的类型(AIO, BIO, NIO)
IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSock ...
- pycham更换主题
在pycham的file-->Setting-->Editor-->Colors&Fonts
- Apache Flink - 基本API概念
Flink程序是实现分布式集合转换的常规程序.集合最初是从源创建的.通过接收器(slink)返回结果,接收器可以将数据写到某个文件或stdout.Flink可以在各种环境(context)中运行,本地 ...
- webpack打包---报错内存溢出javaScript heap out of memory
今天, npm run build打包时,又报内存溢出了.所以记录一下,之前查了博客有一些解释. “报错CALL_AND_RETRY_LAST Allocation failed - JavaScri ...
- 会声会影x7 每次安装均会提示:已安装这个产品的另一个版本
会声会影x7 每次安装均会提示:已安装这个产品的另一个版本 卸载C++2008 的库就行了 文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢迎留言.评论
- CCF认证历年试题
CCF认证历年试题 不加索引整理会死星人orz 第一题: CCF201712-1 最小差值(100分) CCF201709-1 打酱油(100分) CCF201703-1 分蛋糕(100分) CCF2 ...
- XM概述
概述: Extensible Markup Language: 可扩展的标记语言 特点: 语法很严格 标签自定义 作用: * 存储数据 * 做配置文件 * 用于进行数据传输 文档声明: 标示这个文档是 ...
- PHP mysql_num_rows() 函数 返回结果集中行的数目。
定义和用法 mysql_num_rows() 函数返回结果集中行的数目. 语法 mysql_num_rows(data) 参数 描述 data 必需.结果集.该结果集从 mysql_query() 的 ...