Python正则表达式

python正则表达式(Regular Expression):

1、元字符的含义:

元字符是构造正则表达式的一种基本元素;以下为常用的元字符。

'.'表示任意字符:

作用:是匹配除“\n”以外的任何字符,也就是说,它是在一行中进行匹配。

“行”是以“\n”进行区分的。字符串有每行的末尾有一个“\n”,不过它不可见。

'abc'--->'a.'结果为:'ab'
'abc'--->'a.c'结果为:'abc'

注:匹配除换行符以外的任意字符;

\w含义:

匹配[a-zA-Z0-9_]-->1位字母,数字或_或汉字;

\W含义:

\W:匹配任意非数字和字母的字符,相当于[^a-zA-Z0-9_]

\s含义:

匹配任意的空白符;

\d的含义:

匹配任意十进制数,相当于[0-9]-->0123456789任意之一;

\D的含义:

\D:匹配任意非数字字符,相当于[^0-9];

\b的含义:

匹配单词的开始或结束;

'^'表示字符串开头:
'abc'--->'^abc'结果为:'abc';

'$'表示字符串结尾:
'abc'--->'abc$'结果为:'abc'

2、重复限定符

为了处理这些重复问题,正则表达式中一些重复限定符,把重复部分用合适的限定符替代。

'*'表示匹配前一个字符重复0次到无限次;等价于{0,}

'zo*'可以匹配到z, zo, zoo等

'+'表示匹配前一个字符重复1次到无限次;等价于{1,}

'zo+'可以匹配到zo, zoo等
注:'zo+'不能匹配'z'

'?'表示匹配前一个字符重复0次到1次

'zo?'可以匹配到z, zo

'*?','+?','??'前面的*,+,?等都是贪婪匹配,也就是尽可能多匹配;
后面加?号表示使其变成惰性匹配,非贪婪匹配;
abcccd--->abc*?--->ab
abcccd--->abc+?--->abc
abcccd--->abc??--->ab
{m}匹配前一个字符m次:
abcccd--->abc{3}d--->abcccd

例 1:匹配8位数字的QQ号码:

^\d{8}$

例 2:匹配1开头11位数字的手机号码:

^1\d{10}$

{m,}重复m次或更多次:

{m,n}匹配前一个字符m到n次
abcccd--->abc{2,3}d--->abcccd

例 1 匹配银行卡号码是14~18位的数字:

^\d{14, 18}$

{m,n}?匹配前一个字符m到n次,并且取尽可能少的情况
abcccd--->abc{2,3}?--->abc

3、转义

\对特殊字符进行转义,或者是指定特殊序列
a.c--->'a\.c'--->a.c

4、分组:

正则表达式中用小括号()来做分组,也就是括号中的内容作为一个整体。

如:匹配字符串中包含0到多个ab开头:

^(ab)*

5、条件或

正则用符号|来表示或,也叫分支条件,当满足正则里的分支条件的任何一种条件时,都会当成是匹配成功。

^(13[0-2]|15[56]|18[5-6]|145|176)\d{8}$

6、区间

正则提供一个元字符中括号[]来表示区间条件;
限定0到9可以写成:[0-9]

限定A-Z写成:[A-Z]

限定某些数字:[165]

下面,我们来改写下面的正则表达式:

^(130|131|132|155|156|185|186|145|176)\d{8}$

--->

^(130|131|132|155|156|185|186|145|176)\d{8}$

7、实例:正则表达式:

字符串:tel:086-0666-88810009999
原始正则:"^tel:[0-9]{1,3}-[0][0-9]{2-3}-[0-9]{8-11}$"
速记理解:开始"tel:普通文本"[0-9数字]{1至3位}"-普通文本"[0数字][0-9数字]{2至3位}"-普通文本"[0-9数字]{8至11位}结束"
等价简写后正则写法:"^tel:\d{1,3}-[0]\d{2,3}-\d{8,11}$"

8、贪婪模式和惰性模式区别:

贪婪模式:.+

1、贪婪匹配是先看整个字符串是否匹配;
2、如果不匹配,它会去掉字符串的最后一个字符,并再次尝试;
3、如果还不匹配,那么再去掉当前最后一个,直到发现匹配或不剩任何字符。

var str = 'aaa<div style="font-color:red;">123456</div>bbb'
undefined
str.match(/<.+>/);
["<div style="font-color:red;">123456</div>", index: 3, input: "aaa<div style="font-color:red;">123456</div>bbb", groups: undefined]
var str='abcdabceba'
undefined
str.match(/.+b/)
["abcdabceb", index: 0, input: "abcdabceba", groups: undefined]

第一次:(先看整个字符串是否是一个匹配) abcdabceba不匹配,然后去掉最后一个字符a;

第二次:(去掉最后一个字符后再匹配) abcdabceb匹配,返回abcdabceb;

惰性模式:.+?

var str = 'aaa<div style="font-color:red;">123456</div>bbb'
undefined
str.match(/<.+?>/);
["<div style="font-color:red;">", index: 3, input: "aaa<div style="font-color:red;">123456</div>bbb", groups: undefined]
str.match(/.+?b/)
["ab", index: 0, input: "abcdabceba", groups: undefined]

1、惰性匹配是从左侧第一个字符开始向右匹配, 先看第一个字符是不是一个匹配;
2、如果不匹配就加入下一个字符再尝式匹配, 直到发现匹配。
执行str.match(/.+?b/)
第一次:(读入左侧第一个字符)a,不匹配加一个再试;
第二次:ab匹配,返回ab。

9、零宽断言:

断言:正则断言,指明在指定内容的前面或是后面,会出现满足指定规则的内容。

零宽:就是没有宽度,断言只是匹配位置,不占字符,不会返回断言本身。

正则表达式的匹配有两种概念:一种是匹配字符,一种是匹配位置

\b:匹配一个单词的边界,也就是单词和空格间的位置;

例:"er\b"可以匹配"never"中的"er";但是不能匹配"verb"中的"er"。

正则表达式的一种方法,用来查找在某些内容(但并不包括这些内容)之前或之后的东西;

 ^(匹配输入字行首),$(匹配输入字行尾),用于指定一个位置,这个位置应该满足一定的条件(即断言)

断言用来声明一个应该为真的事实,正则表达式中只有当断言为真时,才会继续进行匹配;

9.1、正向先行断言(正前瞻)

语法:(?=exp)

作用:匹配exp表达式前面的内容,不返回本身。

 例1 "I'm singing while you're dancing."获取字符串中的sing和danc字符;

import re
# 匹配的源文本
key = r"I'm singing while you're dancing." # 匹配的正则表达式 # ?=exp:零宽度正预测先行断言,匹配exp前面的位置 # ?=ing:匹配以ing结尾的单词的前面部分(除了ing以外的部分) p1 = r"\b\w+(?=ing\b)" # 编译正则表达式 pattern1 = re.compile(p1) # findall:返回的是所有符合要求的元素列表 # 打印结果:['sing', 'danc'] print(pattern1.findall(key))
import re
# 匹配的源文本
key = "<span class=\"read-count\">阅读数:641</span>"
# 匹配的正则表达式
p1 = r"\d+(?=</span>)"
# 编译正则表达式
pattern1 = re.compile(p1)
# ['641']
print(pattern1.findall(key))

9.2、正向后行断言(正后顾)

语法:(?<=exp)

作用:匹配exp表达式后面的内容,不返回本身。

import re
# 匹配的源文本
key = r"reading a book"
# 匹配的正则表达式
# ?<=exp 匹配exp后面的位置
# ?<=re 会匹配以re开头的单词的后半部分(除了re以外的部分)
p1 = r"(?<=\bre)\w+\b"
# 编译正则表达式
pattern1 = re.compile(p1)
# 打印匹配的结果,findall查找结果返回的是列表
# ['ading']
print(pattern1.findall(key))
import re
# 匹配的源文本
key = "<span class=\"read-count\">阅读数:641</span>"
# 匹配的正则表达式
p1 = r"(?<=<span class=\"read-count\">阅读数:)\d+"
# 编译正则表达式
pattern1 = re.compile(p1)
# ['641']
print(pattern1.findall(key))

9.3、负向先行断言(负前瞻)

语法:(?!exp)

作用:匹配非exp表达式的前面的内容,不返回本身;

import re
# 匹配的源文本
key = r"128e12x8654w856d45y99"
# 匹配的正则表达式
# ?!exp 匹配后面跟的不是exp的位置
# 表示匹配三位数字,而且这三位数字的后面不能是数字;
p1 = r"\d{3}(?!\d)"
# 编译正则表达式
pattern1 = re.compile(p1)
# 打印匹配的结果,findall查找结果返回的是列表
# ['128', '654', '856']
print(pattern1.findall(key))
import re
# 匹配的源文本
key = r"abcd ef cabce ag abc"
# 匹配的正则表达式
# ?!exp 匹配后面跟的不是exp的位置
# 匹配不能以abc开头的单词;
p1 = r"\b((?!abc)\w+)\b"
# 编译正则表达式
pattern1 = re.compile(p1)
# 打印匹配的结果,findall查找结果返回的是列表
# ['ef', 'cabce', 'ag']
print(pattern1.findall(key))
import re
# 匹配的源文本
key = "I love China, I love China very much"
# 匹配的正则表达式
# 匹配不是very much前面的China
p1 = r"China(?!\s\bvery\smuch\b)"
# 编译正则表达式
pattern1 = re.compile(p1)
# ['China']
print(pattern1.findall(key))

9.4、负后后行断言(负后顾)

语法:(?<!exp)

作用:匹配非exp表达式的后面内容,不返回本身。

 例:(?<![a-z])\d{7},匹配不是小写字母开头的七位数字。

10、捕获和非捕获

捕获组:匹配子表达式的内容,把匹配结果保存到内存中,以数字编号或显示命名的组里。

10.1、数字编号捕获组:

语法:(exp)

解释:从表达式左侧开始,每出现一个左括号和它对应的右括号之间的内容为一个分组。

在分组中,第0组为整个表达式,第一组开始为分组。

固定电话:020-85653333

正则表达式为:(0\d{2})-(\d{8})

按照左括号的顺序,这个表达式有如下分组:

用Python来验证一下:

import re
# 匹配的源文本
str = "020-85653333"
# 定义正则表达式,匹配源文本
res = re.match(r"(0\d{2})-(\d{8})", str)
# 获取分组的长度,并循环
for i in range(len(res.groups())+1):
    # 打印分组
    print("第%d个分组为:"%i + res.group(i))

输出结果:

10.2、命名编号捕获组:

语法:(?P<name>exp)

解释:分组的命名由表达式中的name指定。

import re
# 匹配的源文本
str = "020-85653333"
# 定义正则表达式,匹配源文本
# 按名字分组,格式:?P<name>exp,定义正则表达式
res = re.match(r'(?P<quhao>0\d{2})-(?P<haoma>\d{8})', str)
print("分组的个数有:%d"%len(res.groups()))
# 打印分组quhao
print("分组的名称为:quhao,匹配的内容为:%s"%res.group('quhao'))
# 打印分组haoma
print("分组的名称为:haoma,匹配的内容为:%s"%res.group('haoma'))

10.3、非捕获组

语法:(?:exp)

解释:和捕获组刚好相反,用它来标识不需要捕获的分组;可以根据需要去保存你想要的分组。

import re
# 匹配的源文本
str = "020-85653333"
# ?:exp不需要匹配的分组
res = re.match(r"(?:0\d{2})-(\d{8})",str)
# 打印分组的个数
print("分组的个数有:%d"%len(res.groups()))
# 循环分组的内容
for i in range(len(res.groups())+1):
    # 打印分组的内容
    print("第%d个分组为:"%i + res.group(i))

11、反向引用

根据捕获组的命名规则,反向引用可分为:

数字编号组反向引用:\k或\number

命名编号组反向引用:\k或\'name'

通常:捕获组和反向引用是一起使用的。

 

12、实例:获取a标签属性href里面的文本内容:

import re
# 匹配的源文本
key = r"""<br/>您好,非常好,很开心认识你
<br/><a target=_blank href="www.baidu.com">百度一下</a>百度才知道
<br/><a target=_blank href="/view/fafa.htm">发发</a>最佳帅哥
<br/><a target=_blank href="/view/lili.htm">丽丽</a>最佳美女
<br/>"""
# 匹配的正则表达式
# ?<=exp 匹配exp后面的位置
# ?=exp 匹配exp前面的位置
# .*? 惰性匹配,从前往后
p1 = r'(?<=href=").*?(?=">)'
# 编译正则表达式
pattern1 = re.compile(p1)
# 打印匹配的结果,findall查找结果返回的是列表
# ['www.baidu.com', '/view/fafa.htm', '/view/lili.htm']
print(pattern1.findall(key))

 

posted @ 2019-01-08 13:53  云帆济海2017  阅读(297)  评论(0编辑  收藏  举报