【漫漫转码路】Python Day 23

正则表达式

1、贪婪模式

*:对前面的正则表达式匹配0到无穷次
+:对前面的正则表达式匹配1到无穷次
?:对前面的正则表达式匹配0到1次
注意:
只对前面的表达式有效,比如ab*,则只对b重复,
之所以成为贪婪模式,是因为他会尽最大可能的去匹配,能匹配10次,绝对不会匹配9次

# 例如
import re
string = 'abcddddddefg'
p = re.compile('cd*')
m = p.search(string)
print(m)

p1 = re.compile('cd?')
m1 = p1.search(string)
print(m1)

string1 = 'abcgcddddddefg'
p2 = re.compile('cd*')
p3 = re.compile('cd+')
m2 = p2.search(string1)
m3 = p3.search(string1)
print(m2)
print(m3)
# 终端显示
<re.Match object; span=(2, 9), match='cdddddd'>  # *匹配cdddddd
<re.Match object; span=(2, 4), match='cd'>  # ?匹配cd
<re.Match object; span=(2, 3), match='c'>  # *匹配c,此时*取0
<re.Match object; span=(4, 11), match='cdddddd'>  # +匹配cdddddd,因为+不能取0

注意:
这里很奇怪
*和?支持0次,所以存在一种特殊情况,空字符串
同时findall是支持空字符串的,会将空字符串作为列表元素显示出来,如果匹配不到,就会显示空字符串,空字符串的个数和匹配不到的次数+1,结尾必然有一个空字符串

# 例如
import re
string = 'bbbbb'
p = re.compile('a*')
m = p.search(string)
print(m)

string = 'bbbbb'
p = re.compile('a?')
m = p.search(string)
print(m)

string = 'bbbbb'
p = re.compile('a?')
m = p.findall(string)
print(m)

string = 'abbbbb'
p = re.compile('a?')
m = p.findall(string)
print(m)
# 终端显示
<re.Match object; span=(0, 0), match=''>  # 空字符串
<re.Match object; span=(0, 0), match=''>  # 空字符串
['', '', '', '', '', '']  # 一共匹配6次,结尾1次
['a', '', '', '', '', '', '']  # 一共匹配7次,结尾1次

2、非贪婪模式

*?:对前面的正则表达式匹配0到无穷次
+?:对前面的正则表达式匹配1到无穷次
??:对前面的正则表达式匹配0到1次
注意:
之所以成为非贪婪模式,是因为他们在能够匹配的情况下,按照最小次数去匹配
如果将上面程序统一加上?

# 例如
import re
string = 'abcddddddefg'
p = re.compile('cd*?')
m = p.search(string)
print(m)

p1 = re.compile('cd??')
m1 = p1.search(string)
print(m1)

string1 = 'abcgcddddddefg'
p2 = re.compile('cd*?')
p3 = re.compile('cd+?')
m2 = p2.search(string1)
m3 = p3.search(string1)
print(m2)
print(m3)
# 终端显示
<re.Match object; span=(2, 3), match='c'>  # *?最小取0
<re.Match object; span=(2, 3), match='c'>  # ??最小取0
<re.Match object; span=(2, 3), match='c'>  # *?最小取0
<re.Match object; span=(4, 6), match='cd'>  # +?最小取1

3、{}

{m}:将前面的正则表达式重复m次;
{m, n}:将前面的正则表达式重复m-n次,尽可能多的重复,如果忽略m,则最小重复次数默认为0,如果忽略n,则最大重复次数默认无穷大,但是逗号不能忽略;
{m, n}?:非贪婪模式,将前面的正则表达式重复m-n次,尽可能少的重复;
如果m和n都不写,则表示0到无穷次,相当于*

# 例如
import re
string = 'abcddddddefg'
p = re.compile('cd{3}')
m = p.search(string)
print(m)

p1 = re.compile('cd{4,8}')
m1 = p1.search(string)
print(m1)
p1 = re.compile('cd{4,8}?')
m1 = p1.search(string)
print(m1)


string1 = 'abcgcddddddefg'
p2 = re.compile('cd{,8}')
p3 = re.compile('cd{2,}')
m2 = p2.search(string1)
m3 = p3.search(string1)
print(m2)
print(m3)
# 终端显示
<re.Match object; span=(2, 6), match='cddd'>  # 重复3次
<re.Match object; span=(2, 9), match='cdddddd'>  # 4-8次尽可能多的匹配
<re.Match object; span=(2, 7), match='cdddd'>  # 4-8次尽可能少的匹配
<re.Match object; span=(2, 3), match='c'>  # 没有m默认为0
<re.Match object; span=(4, 11), match='cdddddd'>  # 没有n默认无穷大

注意:
在正则表达式中,不要随便加空格,会导致结果改变

# 例如
import re
string = 'ab{3, 5}'
p = re.compile('ab{3, 5}')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(0, 8), match='ab{3, 5}'>  #此时是全匹配,因为在ab{3, 5}中5的前面加了一个空格,他就是正常的字符串,不是特殊字符

4、|

|:任意个正则表达式用|连接,则表示A|B,即A或B,当有一个成功的时候,另外一个则不再匹配

# 例如
import re
string = 'abcddddddefg'
p = re.compile('cd{0}|cd{3}')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(2, 3), match='c'>  # 在匹配到cd{0}之后,就不在匹配另外一个{3}l ,可以看出来,他是从左往右执行
# import re
string = 'abcddddddefg'
p = re.compile('cd{7}|cd{3}')
m = p.search(string)
print(m)
 # 终端显示
 <re.Match object; span=(2, 6), match='cddd'> #左边不符合要求则匹配右边
 # 例如
 import re
string = 'abcddddddefg'
p = re.compile('cd{7}|cd{8}')
m = p.search(string)
print(m)
# 终端显示
None  # 两边都不符合则返回None

5、\

\:1、转义特殊字符串;2、与字符形成特殊序列

转义特殊字符串

# 例如
import re
string = 'abc.'
p = re.compile('.')
m = p.search(string)
print(m)

string = 'abc.'
p = re.compile('\.')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(0, 1), match='a'>  # 转义之前.会表示任一非换行符的字符串
<re.Match object; span=(3, 4), match='.'>  # 转义之后,只会匹配

特殊序列

1、\A:匹配开头,在re.M情况下,不会判断每行的开始

# 例如
import re
string = 'abcdefg'
p = re.compile('\Aa')
m = p.search(string)
print(m)

import re
string = 'abcd\nefg'
p = re.compile('\Aa',flags=re.M)
m = p.findall(string)
print(m)
# 终端显示
<re.Match object; span=(0, 1), match='a'>
['a']  # re.M模式也一样

2、\b:匹配空字符串,但是只会在单词边界(空格,换行,制表)的开头或结尾位置

# 例如
import re
string = 'abcdefg'
p = re.compile(r'g\b')
m = p.search(string)
print(m)

string = 'abcd e fg'
p = re.compile(r'\be\b')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(6, 7), match='g'>  # 相当于匹配结尾
<re.Match object; span=(5, 6), match='e'>  # 匹配中间隔开的e

3、\B:匹配非单词边界的空字符串

# 例如
import re
string = 'abcdefg'
p = re.compile(r'g\B')
m = p.search(string)
print(m)

string = 'abcd e fg'
p = re.compile(r'\Bb\B')
m = p.search(string)
print(m)
# 终端显示
None  # 发现结尾的g匹配不到了
<re.Match object; span=(1, 2), match='b'>  #可匹配到中间的b

4、\d:任意一个十进制的数,即(0-9)

# 例如
import re
string = '123456789abc'
p = re.compile(r'\d')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(0, 1), match='1'>  # 匹配到1

5、\D:任意一个非数字字符

# 例如
import re
string = '123456789abc'
p = re.compile(r'\D')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(9, 10), match='a'>  # 匹配到a

6、\s:任意一个空白字符(空格,换行,制表)

# 例如
import re
string = 'adb a bcd'
p = re.compile(r'a\sb')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(4, 7), match='a b'>

7、\S:任意一个非空白字符

# 例如
import re
string = 'adb a bcd'
p = re.compile(r'a\Sb')
m = p.search(string)
print(m)
# 终端显示
<re.Match object; span=(0, 3), match='adb'>

8、\w:一个字母或数字或下划线

# 例如
import re
string = '123_a 56_'
p = re.compile(r'\w*')
m = p.findall(string)
print(m)
# 终端显示
['123_a', '', '56_', '']  # 可以看到中间空格部分输出是空字符串

9、\W:一个非字母数字或下划线

# 例如
import re
string = '123_a 56_'
p = re.compile(r'\W*')
m = p.findall(string)
print(m)
# 终端显示
['', '', '', '', '', ' ', '', '', '', '']  # 可以看到除了中间空格外,都是空字符串

10、\Z:只匹配字符串的结尾,在re.M情况下,不会判断每个换行符的前面

# 例如
import re
string = 'abcdefg'
p = re.compile('g\Z')
m = p.search(string)
print(m)

string = 'abcd\nefg'
p = re.compile('d\Z', flags=re.M)
m = p.findall(string)
print(m)
# 终端显示
<re.Match object; span=(6, 7), match='g'>
[]  # re.M模式下也一样

只有\Z的时候,匹配一个空字符串

# 例如
import re
string = 'abcdefg'
p = re.compile('\Z')
m = p.findall(string)
print(m)
# 终端显示
['']

6、[]

[]:字符集
[amk]等价于’a’|‘m’|‘k’
[a-y]:匹配a到y之间的小写字母
[0-5]:匹配0到5之间的数字
[0-5][a-y]:匹配两个字符
[.+]:特殊字符在字符集中会失去特殊含义,只能代表普通字符,相当于转义,但是斜杠加字母的特殊序列可以被接受
[]:在[]中,会表示取反

# 例如
import re
string = '123_abc'
p = re.compile('[^_]')
m = p.findall(string)
print(m)
# 终端显示
['1', '2', '3', 'a', 'b', 'c']  # ^_表示除了_以外的字符

注意:

# 例如
import re
string = '[]'
p = re.compile('[[]]')
m = p.findall(string)
print(m)

import re
string = '[]'
p = re.compile('\[\]')
m = p.findall(string)
print(m)

import re
string = '[]'
p = re.compile('[\[\]]')
m = p.findall(string)
print(m)
# 终端显示
['[]']  #和一起的
['[]']  # 和一起的
['[', ']']  # 在方括号[]里面,所以显示也是分开的

7、()

(1)捕获分组,匹配括号内任意正则表达式,并表示出开始和结尾,整个正则表达式是0组,里面的括号从1开始编号

# 例如
import re
p = re.compile('b.+a.+e')
m = p.match('babacdefg')
print(m)

p = re.compile('b(.+)a(.+)e')
m = p.match('babacdefg')
print(m.group(1))  # 获取1组的内容
print(m.group(1,2))  # 1组和2组的内容
print(m.groups())  #groups返回所有子组结果
# 终端显示
<re.Match object; span=(0, 7), match='babacde'>
ab
('ab', 'cd')  # 结果是元组形式
('ab', 'cd')  # 显示所有子组

groups(default = None):当返回的子组没有参与匹配的时候,默认返回None,同时可以捕获所有子组结果,结果以元组的形式呈现
start(groups):返回该组起始位置,当该组没有匹配的时候返回-1
end(groups):返回该组结束位置,左闭右开,当该组没有匹配的时候返回-1
span(groups):返回该组索引,左闭右开,相当于把start和end结合起来
组如果嵌套起来,0组等于1组

# 例如
import re
p = re.compile('b(.+)(.+)?(.+)?')
m = p.match('babacdefg')
print(m.group(1))
print(m.group(1, 2))
print(m.groups('NO'))
print(m.start(1))
print(m.start(2))
print(m.end(1))
print(m.end(3))
print(m.span(1))
print(m.span(2))
# 终端显示
abacdefg
('abacdefg', None)
('abacdefg', 'NO', 'NO')
1  # start可以传组,返回该组起始位置
-1  # 当该组没有匹配的时候返回-1
9
-1
(1, 9)
(-1, -1)
# 例如
import re
p = re.compile('(b(.+)(.+)?(.+)?)')
m = p.match('babacdefg')
print(m.group(1))
print(m.group(0))
print(m.group(2))
# 终端显示
babacdefg
babacdefg
abacdefg

后面加\数字表示和前面一样的重复次数

# 例如
import re
p = re.compile(r'(.+) \1')
m = p.match('bab babcdefg')
print(m)

p = re.compile(r'(.+) (.+)')
m = p.match('bab babcdefg')
print(m)
# 终端显示
<re.Match object; span=(0, 7), match='bab bab'>
<re.Match object; span=(0, 12), match='bab babcdefg'>

如果有捕获分组的时候,findall只会捕获分组里面的内容

# 例如
import re
p = re.compile('b(.+)a(.+)e')
m = p.findall('babacdefg')
print(m)
# 终端显示
[('ab', 'cd')]

匹配()可以加\或者放到[]中去

(2)(?:…)

(?:…):非捕获分组,非捕获分组不会形成子组

# 例如
import re
p = re.compile('b(?:.+)a(.+)e')
m = p.findall('babacdefg')
print(m)
m = p.match('babacdefg')
print(m.groups())
print(m.group(1))
# 终端显示
['cd']  # 显示只有一个组
('cd',)
cd

(3)(?=…)

(?=…):前向肯定界定符,不参与匹配结果,只参与匹配判定,如果判定为真,则继续,如果判定失败,则返回None

# 例如
import re
p = re.compile('.*[.](?=exe$).+')  # 判定是否以exe结尾,如果是,继续进行,不是,返回空
m = p.findall('abc.exe')
print(m)

p = re.compile('.*[.](?=exe$)')
m = p.findall('abc.exe')
print(m)

p = re.compile('.*[.](?=exe$)')
m = p.findall('abc.exa')
print(m)
# 终端显示
['abc.exe']  # 只参与判定,不参与匹配
['abc.']  # 你看,如果去掉最后的.+就停在了abc.,因为后面没有了
[]  # 判定失败

(4)(?!…)

(?!…):前向否定界定符,不参与匹配结果,只参与匹配判定,如果判定为假,则继续,如果判定为真,则返回None

# 例如
import re
p = re.compile('.*[.](?!exe$).+')  # 匹配成功,返回空
m = p.findall('abc.exe')
print(m)

p = re.compile('.*[.](?!exe$)')
m = p.findall('abc.exe')
print(m)

p = re.compile('.*[.](?!exe$).+')  # 匹配失败,继续往下
m = p.findall('abc.exa')
print(m)
# 终端显示
[]
[]
['abc.exa']

8、p.split()

p.split(string, maxsplit = 0):用子字符串(就是compile里面的字符串)把字符串string进行分割,以列表形式返回,maxsplit = 0最大分割次数,默认为0

# 例如
import re
p = re.compile('\W+')
m = p.split('word, word, word.')
print(m)

p = re.compile('(\W+)')  # 有捕获分组
m = p.split('word, word, word.')
print(m)

p = re.compile('\w+')  # 开头就是一刀
m = p.split('word, word, word.')
print(m)
# 终端显示
['word', 'word', 'word', '']
['word', ', ', 'word', ', ', 'word', '.', '']  # 有捕获分组,分组内容也显示
['', ', ', ', ', '.']  # 开头有一刀的话,在最开始有一个''

9、p.sub()

p.sub(repl, string, count=0):替换,将repl替换掉string中的子字符串(就是compile)
第一个repl可以是字符串,还可以是函数

# 例如
import re
p = re.compile(r'blue|white|red')
print(p.sub('colour', 'blue socks and red shoes'))
print(p.sub('colour', 'blue socks and red shoes',count=1))
# 终端显示
colour socks and colour shoes  # 先匹配,然后将匹配到的东西替换掉
colour socks and red shoes  # 限制替换次数

当repl是函数

# 例如
import re
def func(matchobj):
    if matchobj.group(0) == '-':
        return ' '
    else:
        return '-'

        
p = re.compile(r'-{1,2}')  # 先匹配,将匹配到的字符串作为参数,返回一个match对象,将match对象传入函数中,然后执行函数体,将返回的结果替换掉原字符串的相关东西,注意匹配的时候是非重叠对象
print(p.sub(func, 'pro----gram-files'))
# 终端显示
pro--gram files

9、p.subn()

p.subn(repl, string, count=0):替换,将repl替换掉string中的子字符串(就是compile)
第一个repl可以是字符串,还可以是函数,多返回一个替换次数,以元组形式返回

# 例如
import re
def func(matchobj):
    if matchobj.group(0) == '-':
        return ' '
    else:
        return '-'


p = re.compile(r'-{1,2}')
print(p.subn(func, 'pro----gram-files'))
# 终端显示
('pro--gram files', 3)

10、模块级别函数

re.对象方法.(编译内容,string,flags = 0)
形式简单,但是占用内存,省去了编译的过程

# 例如
import re
def func(matchobj):
    if matchobj.group(0) == '-':
        return ' '
    else:
        return '-'


p = re.compile(r'-{1,2}')
print(p.subn(func, 'pro----gram-files'))

print(re.subn(r'-{1,2}', func, 'pro----gram-files'))
# 终端显示
('pro--gram files', 3)
('pro--gram files', 3)  # 可以看到结果一致

11、re.X或re.VERBOSE

正则表达式可以加空白符(空格,换行,制表)

# 例如
import re
# 等价于 p = re.compile(r"\d+\.\d*")
p = re.compile(r"""
                \d + # 匹配整数部分, re.X使得该空格不影响
                \. # 匹配小数点, re.X使得可以分段写
                \d * # 匹配小数部分, re.X使得该空格不影响
                """, re.X)
print(p.findall("1.2345.78"))  # 换行用三引号
# 终端显示
['1.2345']  # 不影响结果

你可能感兴趣的:(转码,python,正则表达式,改行学it,人工智能,深度学习)