[Python进阶]Python正则表达式

[Python进阶]Python正则表达式

一、元字符

.匹配除换行符之外的任何字符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
^ 匹配字符串的开头
$ 匹配字符串的末尾或字符串末尾的换行符之前
re* 重复匹配前面的字符零次或者更多次(贪婪模式:尽可能多的匹配遇到的重复)
re+重复匹配前面的字符1次或者更多次(贪婪模式)
re? 重复匹配前面的字符0次或者1次(非贪婪模式)
re{m} 重复匹配m次,例如,"o{2}“不能匹配"Bob"中的"o”,但是能匹配"food"中的两个o。
re{n, }精确匹配n个前面表达式。例如,"o{2,}“不能匹配"Bob"中的"o”,但能匹配"foooood"中的所有o。"o{1,}“等价于"o+”。“o{0,}“则等价于"o*”。
re{m,n} 重复匹配m次或者n次(贪婪模式)
re{m,n}? {m,n}的非贪婪模式.
\\ 转义特殊字符或表示特殊序列
[...] 表示一组字符,如果以”^"为第一个字符,表示一组字符的互补集.
| A|B, 选择分支,或者匹配A或者匹配B.

二、分组

(...)(正则表达式分组):就是用一对圆括号“()”括起来的正则表达式。使用group(num)和groups()函数提取分组内容。group(0)提取整个正则表达式内容。
(?P<name>...)(命名分组):就是给具有默认分组编号的组另外再给一个别名。
(?P=name)\数字(后向引用):①以前面的以name为名称的组匹配的文本为分组内容,匹配后面的内容②,\n表示引用第n个组。而\0则引用整个被匹配的正则表达式本身。后向引用用于匹配一些重复的字符串。
(?=pattern)(前向肯定断言):当该表达式匹配成功的时候,它的前面的表达式才会匹配.
(?<=pattern)(后向肯定断言):匹配以pattern开始的后面部分的字串,pattern只能是一个明确的表达式.
(?!pattern)(前向否定断言):当该表达式不匹配的时候,它的前面的表达式都会匹配成功
(?<!pattern)(后向否定断言):匹配不是以pattern开始的后面部分的字串.只能是固定的长度

>>>print(re.match('(?P<first_name>\w+) (?P<last_name>\w+)','Eric Brown').group())
Eric Brown
#通过命名分组进行后向引用
>>> re.search(r'(?P<name>go)\s+(?P=name)\s+(?P=name)', 'go go go').group('name')
'go'
#通过默认分组编号进行后向引用
>>> re.search(r'(go)\s+\1\s+\1', 'go go go').group()
'go go go'
#交换字符串的位置
>>> s = 'abc.xyz'
>>> re.sub(r'(.*)\.(.*)', r'\2.\1', s)
'xyz.abc'
#如果在匹配的过程中,需要同时用到前向肯定断言和后向肯定断言,那么必须将后向肯定断言写在正则语句的前面,前向肯定断言写在正则语句的后面,表示后向肯定模式之后,前行肯定模式之前。
>>> s1='''char *a="hello world"; char b='c'; /* this is comment */ int c=1; /* this is multiline comment */'''
>>> re.findall( r'(?<=/\*).+?(?=\*/)' , s1 ,re.M|re.S)
[' this is comment ', ' this is multiline comment ']
#肯定断言
>>> print(re.match('(?<=abc)def', 'abcdef'))
None
>>> print(re.search('(?<=abc)def', 'abcdef'))
<_sre.SRE_Match object; span=(3, 6), match='def'>
>>> print(re.match('(\w+)(?<=zhang)san', 'myzhangsan').group())
myzhangsan
#否定断言

三、特殊字符序列

\number
\A:匹配字符串开始。
\Z:匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\b:匹配一个单词边界。\b可以匹配的边界包括单词和特殊字符边界,比如$,#…等。
\B:匹配非单词边界
\d:匹配任意数字,等价于 [0-9]。
\D:匹配任意非数字
\s:匹配任意空白字符,等价于 [\t\n\r\f]。
\S: 匹配任意非空字符
\w:匹配数字字母下划线
\W:匹配非数字字母下划线

四、正则表达式常用方法(函数)

compile

compile 函数用于编译正则表达式,返回编译后的正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
re.compile(pattern[, flags])

  • pattern : 一个字符串形式的正则表达式
  • flags 可选,表示匹配模式,具体参数为:
    • re.I(re.IGNORECASE): 忽略大小写
    • re.M(MULTILINE): 多行模式,使"^"和“$”能在一个换行符后继续使用。
    • re.S(DOTALL): 点任意匹配模式,使"."能够匹配包括换行符的所有字符.
    • re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
    • re.U(UNICODE): 仅供兼容性。忽略字符串模式(默认),并且禁止字节模式。
    • re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
>>> p=re.compile('\d{4}\-\d{7}',re.A)
>>> print(type(p))
<class 're.Pattern'>
match

从头开始匹配一个正则表达式模式,如果匹配,则返回一个match对象,如果不匹配,则返回None,即使在多行模式下,匹配也是从整个字符串的开头开始,而不是从每行的开头开始。
match(pattern, string, flags=0)
group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

# ip地址的匹配:正则(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])
#1.直接由re调用match进行匹配
>>> m=re.match(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])','192.168.1.1')
>>> print(type(m))
<class 're.Match'>
>>> print(m.group())
192.168.1.1
#2.利用pattern对象进行匹配
>>> p=re.compile(r'(\d{1,3}\.){3}(\d{1,3})')
>>> m=p.match('192.168.1.1')
>>> print(type(m))
<class 're.Match'>
>>> print(m.group())
192.168.1.1
#正则匹配部分字符串,但不是整个字符串
>>> m=p.match('192.168.1.1 is my ip address')
>>> print(m)
<re.Match object; span=(0, 11), match='192.168.1.1'>
fullmatch

完全匹配,如果整个字符串匹配正则表达式,才会返回match对象,如果不匹配或有部分匹配,返回None.
fullmatch(pattern, string, flags=0)

search

在字符串中搜索是否存在模式,不是从字符串的开头进行匹配,而是在整个字符串的所有位置进行查找,返回第一个符合条件的字符的match对象,并不会判断一个字符串有几个匹配。
search(pattern, string, flags=0)

sub

替换字符串中出现的符合表达式的字符串,如果替换成功,则返回替换后的字符串,如果没有替换成功,则返回原字符串。
re.sub(pattern, repl, string, count=0, flags=0)

  • repl:要替换的字符串,可以是一个字符串,也可以是一个函数(方法),字符串中也可以含有正则。
  • count : 模式匹配后替换的最大次数,默认0表示替换所有的匹配。
>>> phone = "2004-959-559 # 这是一个电话号码"
>>> num = re.sub(r'#.*$', "", phone) # 删除注释
>>> print (num)
2004-959-559  
>>> num = re.sub(r'\D', "", phone)# 移除非数字的内容
>>> print (num)
2004959559
#改变日期的格式
>>> s = '2017-11-27'
>>> import re
>>> print(re.sub('(\d{4})-(\d{2})-(\d{2})',r'\2/\3/\1', s))
11/27/2017

# repl 参数是一个函数
def double(matched):#将匹配的数字乘于 2
    value = int(matched.group('value'))
    return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))
#A46G8HFD1134
subn

subn返回的是一个tuple,在该tuple中,有两个值,前面是返回的替换后的字符串,后面是替换的次数。

split

利用与表达式匹配的子字符串分割给定字符串, 返回的值是一个分割后的列表。
split(pattern, string, maxsplit=0, flags=0)

>>> re.split('\W+', 'runoob, runoob, runoob.')
['runoob', 'runoob', 'runoob', '']
>>> re.split('(\W+)', ' runoob, runoob, runoob.') 
['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
>>> re.split('\W+', ' runoob, runoob, runoob.', 1) 
['', 'runoob, runoob, runoob.']
>>> re.split('a*', 'hello world')   # 对于一个找不到匹配的字符串而言,split 不会对其作出分割
['hello world']
findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
matchsearch 是匹配一次 findall 匹配所有。
re.findall(string[, pos[, endpos]])

>>> import re
>>> s = "adfad asdfasdf asdfas asdfawef asd adsfas " 
>>> reObj1 = re.compile('((\w+)\s+\w+)')>>> reObj1.findall(s)
[('adfad asdfasdf', 'adfad'), ('asdfas asdfawef', 'asdfas'), ('asd adsfas', 'asd')] 
>>> reObj2 = re.compile('(\w+)\s+\w+')>>> reObj2.findall(s)
['adfad', 'asdfas', 'asd']
>>> reObj3 = re.compile('\w+\s+\w+')>>> reObj3.findall(s)
['adfad asdfasdf', 'asdfas asdfawef', 'asd adsfas']

①.当给出的正则表达式中带有多个括号时,列表的元素为多个字符串组成的tuple,tuple中字符串个数与括号对数相同,字符串内容与每个括号内的正则表达式相对应,并且排放顺序是按括号出现的顺序。
②.当给出的正则表达式中带有一个括号时,列表的元素为字符串,此字符串的内容与括号中的正则表达式相对应(不是整个正则表达式的匹配内容)。
③当给出的正则表达式中不带括号时,列表的元素为字符串,此字符串为整个正则表达式匹配的内容。

finditer

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个match迭代器返回。
finditer(pattern, string, flags=0)

it = re.finditer(r"\d+","12a32bc43jf3") 
for match in it: 
    print (match.group() ) #12 32 43 3
escape

转义字符串中所有的非数字字母字符。当要匹配的字符串含有正则表达式的元字符的时候,可以先利该方法进行转义。

#如我们需要匹配一个字符串中的文件名,test.py,可以用如下的表达式:
>>> print(re.findall(re.escape('test.py'),'I hava a test.py in the folder named test_py'))
['test.py']
>>> print(re.findall('test.py','I hava a test.py in the folder named test_py'))
['test.py', 'test_py']
start()、end()、span()

start()返回匹配的起始位置。索引位置是从0开始计数的。
end()返回匹配结束的下一个位置。
span()返回匹配的区间,左闭右开。

>>> re.search(r'\d+', 'asdf13df234').start()
4 
>>> re.search(r'\d+', 'asdf13df234').end()
6
>>> re.search(r'\d+', 'asdf13df234').span()
(4, 6)

扩展阅读
python 正则表达式findall匹配问题

发布了54 篇原创文章 · 获赞 3 · 访问量 3657

猜你喜欢

转载自blog.csdn.net/magic_jiayu/article/details/104086813