四、分支条件|

正则表达式也支持类似于OR的方式,使用“|”符号连接几个表达式,只要其中一个表达式匹配上就算匹配。

1
2
3
4
5
6
7
8
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'123|879')  #匹配数字123 或者是879
pattern2 = re.compile(r'abcd|gmail')   #匹配字符是abcd 或者是gmail
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['123', '879']
['gmail']

五、注释(?#…)

(?#…)来表示注释。括号内的内容会被忽视。注释内容并不影响匹配结果,仅仅是说明作用。

1
2
3
4
5
6
7
8
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'123|879(?#匹配数字123 或者是879)')
pattern2 = re.compile(r'abcd|gmail(?#匹配字符是abcd 或者是gmail)')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['123', '879']
['gmail']

前面讲过,三重引号的多行字符串,可以添加注释。那么如果把正则表达式写成多行的话,也可以添加注释。这种情况下,需要VERBOSE(也可使用简略写法X)标志,上面的例子可以修改如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = r'''
123  #T注释1 匹配数字123 或者是879
|    #T注释2 匹配数字123 或者是879
879  #T注释3 匹配数字123 或者是879
'''
pattern2 = r'''
abcd  #T注释1 匹配字符是abcd 或者是gmail
|     #T注释2 匹配字符是abcd 或者是gmail
gmail #T注释3 匹配字符是abcd 或者是gmail
'''
item1 = re.findall(pattern1,string,re.VERBOSE)
item2 = re.findall(pattern2,string,re.VERBOSE)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['123', '879']
['gmail']

六、贪婪匹配与懒惰匹配

正则表达式默认匹配尽可能多的字符。

1
2
3
4
5
import re
string = 'test1234@gmail.com或13076879876电话'
pattern = re.compile(r'\w*t')
item = re.search(pattern,string)
print(item.group())

执行以上程序会输出如下结果:

1
test

*匹配了尽可能多的字符test,这种匹配模式就被称为贪婪模式。 但是有时候我们的需求是需要匹配尽可能少的字符,这种方式在正则表达式中被成为懒惰模式。需要匹配懒惰模式,只需要在限定符后面加入一个?就可以了。

1
2
3
4
5
import re
string = 'test1234@gmail.com或13076879876电话'
pattern = re.compile(r'\w*?t')
item = re.search(pattern,string)
print(item.group())

执行以上程序会输出如下结果:

1
t

懒惰模式有以下几种形式:
*?重复任意次,但是匹配尽可能少的字符。
+?重复1次或者多次,但是匹配尽可能少的字符。
??重复0次或者1次,但是匹配尽可能少的字符。
{n,}?重复n次以上,但是匹配尽可能少的字符。
{n,m}?重复n次到m次,但是匹配尽可能少的字符。

“*?“的用法:

1
2
3
4
5
6
7
8
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'\w*t')
pattern2 = re.compile(r'\w*?t')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['test']
['t', 'est']

”+?“的用法:

1
2
3
4
5
6
7
8
import re
string = 'test1234t@gmail.com或13076879876电话'
pattern1 = re.compile(r'\w+t')
pattern2 = re.compile(r'\w+?t')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['test1234t']
['test', '1234t']

”??“的用法:

1
2
3
4
5
6
7
8
import re
string = 'ttest1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'\w?t')
pattern2 = re.compile(r'\w??t')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['tt', 'st']
['t', 't', 'st']

”{n,}?“的用法:

1
2
3
4
5
6
7
8
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'\w{2,}')
pattern2 = re.compile(r'\w{2,}?')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['test1234', 'gmail', 'com或13076879876电话']
['te', 'st', '12', '34', 'gm', 'ai', 'co', 'm或', '13', '07', '68', '79', '87', '6电']

”{n,m}?“的用法:

1
2
3
4
5
6
7
8
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'\w{2,4}')
pattern2 = re.compile(r'\w{2,4}?')
item1 = re.findall(pattern1,string)
item2 = re.findall(pattern2,string)
print(item1)
print(item2)

执行以上程序会输出如下结果:

1
2
['test', '1234', 'gmai', 'com或', '1307', '6879', '876电']
['te', 'st', '12', '34', 'gm', 'ai', 'co', 'm或', '13', '07', '68', '79', '87', '6电']

七、分组

分组就是将整个正则表达式分成不同的组,只获取不同组匹配的内容。其中分组使用“()”来区分,括号内匹配的内容为一个组。 示例如下:

1
2
3
4
5
6
7
8
9
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'(test).*(13).*(电话)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))  #输出[('test', '13', '电话')]。

print('总共匹配到%s个数据。'%len(item1.groups()))
for i in range(len(item1.groups())+1):
    print('第%d个数据是:%s'%(i,item1.group(i)))

执行以上程序会输出如下结果:

1
2
3
4
5
6
[('test', '13', '电话')]
总共匹配到3个数据。
0个数据是:test1234@gmail.com或13076879876电话
1个数据是:test
2个数据是:13
3个数据是:电话

可以看到,(test).(13).(电话)共有三个组,分别匹配了’test’, ‘13’, ‘电话’。 item1的结果是个group组,默认索引从0开始。除了使用数字索引外,还可以重命名组名。

重命名组名(?P<name>pattern)
使用“(?P<name>pattern)”可以重命名组名。

1
2
3
4
5
6
7
8
9
import re
string = 'test1234@gmail.com或13076879876电话'
pattern1 = re.compile(r'(?P<第一个匹配项>test).*(?P<第二个匹配项>13).*(?P<第三个匹配项>电话)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))  #输出[('test', '13', '电话')]。

print(item1.group("第一个匹配项"))
print(item1.group('第二个匹配项'))
print(item1.group('第三个匹配项'))

执行以上程序会输出如下结果:

1
2
3
4
[('test', '13', '电话')]
test
13
电话

八、后向引用

\number
可以用来匹配与某个分组相同的部分,提供查找重复字符组的方便的方法。组从1开始编号,只能用于匹配前99个组中的1个。 如果数字的第一个数字是0,或者数字是3个八进制数字,则不会将其解释为组匹配,而是解释为具有八进制数值的字符。

我们可以通过示例来进行了解。

1
2
3
4
5
import re
string = 'test1234@gmail.com或test1237@gmail.com或test1289@gmail.com'
pattern1 = re.compile(r'(test\d+).*?(test\d+).*?(test\d+)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))

执行以上程序会输出如下结果:

1
[('test1234', 'test1237', 'test1289')]

第一组匹配的是test1234 第二组匹配的是test1237 第三组匹配的是test1289

现在来实现第一组和第二组匹配相同的内容,也就是test1234和test1237相同的部分test123。 只需要将第二组的test\d+修改为\1。

1
2
3
4
5
import re
string = 'test1234@gmail.com或test1237@gmail.com或test1289@gmail.com'
pattern1 = re.compile(r'(test\d+).*?(\1).*?(test\d+)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))

执行以上程序会输出如下结果:

1
[('test123', 'test123', 'test1289')]

第一组匹配的是test1234 第二组匹配的是test1237

现在来实现第二组和第三组匹配相同的内容,也就是test1237和test1289相同的部分test12。 只需要将第三组的test\d+修改为\2。

1
2
3
4
5
import re
string = 'test1234@gmail.com或test1237@gmail.com或test1289@gmail.com'
pattern1 = re.compile(r'(test\d+).*?(test\d+).*?(\2)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))

执行以上程序会输出如下结果:

1
[('test1234', 'test12', 'test12')]

现在来实现第一组,第二组和第三组匹配相同的内容,也就是test1234,test1237和test1289相同的部分test12。 只需要将第二组的test\d+修改为\1,第三组的test\d+修改为\2。

1
2
3
4
5
import re
string = 'test1234@gmail.com或test1237@gmail.com或test1289@gmail.com'
pattern1 = re.compile(r'(test\d+).*?(\1).*?(\2)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))

执行以上程序会输出如下结果:

1
[('test12', 'test12', 'test12')]

如果已经给分组进行了命名呢?也没有问题,只需要将代表分组号码的”\1”换为分组名称”?P=…“即可。
(?P=name)
对已命名组的后向引用;它匹配与先前名为name的组匹配的任何文本。

下面第二组引用第一组的名字aaa。需要注意的是,用名字引用的匹配结果是不会显示的。

1
2
3
4
5
import re
string = 'test1234@gmail.com或test1237@gmail.com或test1289@gmail.com'
pattern1 = re.compile(r'(?P<aaa>test\d+).*?(?P=aaa).*?(test\d+)')
item1 = re.match(pattern1,string)
print(re.findall(pattern1,string))

执行以上程序会输出如下结果:

1
[('test123', 'test1289')]

第二组的引用’test123’没有显示出来。


转载请注明本网址。