一、什么是正则表达
字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的 Email 地址,虽然可以编程提取 @ 前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
所以我们判断一个字符串是否是合法的 Email 的方法是:
1. 创建一个匹配 Email 的正则表达式;
2. 用该正则表达式去匹配用户的输入来判断是否合法。
因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。
二、python中的正则表达--re模块
1、findall()方法
我们先来举个例子看看python为我们封装好的re模块
import re #导入我们的re模块(如果没有请用conda或者pip下载)
pattern = r'westos' #匹配的规则为 'westos'
s = 'westos hgkjtrgtrigjo westos' #这里是用规则去寻找的对象
print(re.findall(pattern, s)) #调用re.findall方法,其中传入两个参数:第一个为正则的方法,第二个为对象
分析:我们的规则就是去寻找符合‘westos’规则的内容,并且打印出来,在我们的对象中有两个是符合的,我们通过正则表达找到并且打印出来;
2、match()方法
match() 方法判断是否匹配,如果匹配成功,返回一个 Match 对象,否则返回 None 。
常见的判断方法就是:例如
上面的两个结果给我们看到了match的结果,当匹配的为合法对象时,则返回一个对象;若为不合法对象则返回一个空;
那么你可能要问了,这么简单的我凭着肉眼就能找到了,还需要这么麻烦码?
那么如果你要处理的文件有几个G的大小你还觉得简单的吗?如果是要是筛查变量是否合法,邮箱地址是否合法,用户名是否合法?那么你还觉得re模块简单吗?
二、正则的基础语法
1、单个字节匹配:
\d 代表:匹配单个数字
\D 代表:匹配非单个数字
\s 代表:匹配任何空白字符,包括空格、制表符、换页符等等
\S 代表:匹配任何非空白字符
\w 代表:匹配单个字母, 数字或者下划线,在python3.x中还可以匹配中文
\W 代表:匹配非单个数字,字母或者下划线
. 代表任意单个字符
2、任意字节匹配;
要匹配变长的字符,在正则表达式中,
用 * 表示任意个字符(包括 0 个),
用 + 表示至少一个字符,
用 ? 表示 0 个或 1 个字符,
用 {n} 表示 n 个字符,
用 {n,m} 表示 n~m 个字符:
3、精确的匹配可以用[ ]
[^abc] 除了a b c之外的其他字符
[0-9a-zA-Z\_] 可以匹配一个数字、字母或者下划线;
[0-9a-zA-Z\_]+ 可以匹配至少由一个数字、字母或者下划线组成的字符串;比如 'a100' , '0_Z' , 'Py3000' 等等;
[a-zA-Z\_][0-9a-zA-Z\_]* 可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是 Python 合法的变量;
[a-zA-Z\_][0-9a-zA-Z\_]{0, 19} 更精确地限制了变量的长度是 1-20 个字符(前面1 个字符+后面最多 19 个字符)
4、其他
‘|’--A|B 可以匹配 A 或 B,所以 [P|p]ython 可以匹配 'Python' 或者 'python' 。
^ 表示行的开头, ^\d 表示必须以数字开头。
$ 表示行的结束, \d$ 表示必须以数字结束。
你可能注意到了, py 也可以匹配 'python' ,但是加上 ^py$ 就变成了整行匹配,就只能匹配 'py' 了
5、正则表达中,特殊字符需要用\来转译
例如 : \*,\+, \?, \.等
上面罗列的这些语法也许看着就像是天书,据几个例子来看看也许你会明白许多;
例1:
import re
# pattern = r""
# s = ""
# re.findall(pattern, s)
print(re.findall(r'(\d+)', '全班人数为100'))
print(re.findall(r'\D+', '阅读人数为100'))
print(re.findall(r'\s+', '\t阅读人数为100\n\r '))
print(re.findall(r'\S+', '\t阅读人数为100\n\r '))
print(re.findall(r'\w+', 'root email: he_llo@163.com'))
print(re.findall(r'\W+', 'root email: he_llo@163.com'))
第一句:匹配全部的数字(加号代表有一个或者多个)
第二句:匹配非数字
第三句:匹配任何空白字符,包括空格、制表符、换页符
第四句:匹配非空白字符,包括空格、制表符、换页符
第五句:匹配数字、字母、下划线,也可以匹配中文
第六句:匹配非数字、字母、下划线、中文
例2:
import re
print(re.findall(r'1+', '读阅人数为1000, 11, 1111, 00'))
print(re.findall(r'\d+', '读阅人数为1000, 11, 111, 100'))
print(re.findall(r'westo*s', 'westooos wests westas'))
第一句:匹配有一个或者多个1的
第二句:匹配数字
第三句:匹配o有零个或者多个
上面的两个例字首先要看出*(零个或多个)和+(一个或多个)的区别;
例3:
现在有一个实际需求,需要去判断用户输入的电话号码是否合法
要求:电话必须为11位;并且必须是‘1’开头
import re
s = input('you number:')
pattern = r'1\d{10}'
if re.match(pattern,s):
print('ok')
else:
print('\nError')
三、匹配一个邮箱地址
1、匹配163邮箱;xxxxxx@163.com
规则:6~18个字符,可使用字母、数字、下划线;开头必须为字母
import re
a = """
kevintian126@126.com
1136667341@qq.com
meiya@cn-meiya.com
wq901200@hotmail.com
111meiyahr@163.com
meiyuan@0757info.com
chingpeplo@sina.com
tony@erene.com.com
melodylu@buynow.com
aaa666777@163.com
"""
q = re.findall(r'\w{6,18}@163\.com',a) #匹配了一个163邮箱
print(q)
for email in q:
matchobj = re.match(r'^[a-zA-Z].*',email)
if matchobj:
print(matchobj.group())
else:
print('')
上面我们一共分了2步来筛查163邮箱;
第一:我们先把所有的163邮箱拿出来,返回的是一个列表
第二:我们把以字母开头的所有163邮箱再次筛查出来,最后得我们的要求;
2、我们还可以变化需求,把合法的邮箱地址全部过滤出来
import re
from itertools import chain
s = """
你好,各种格式的邮箱入下所示:
kevintian126@126.com
2. 1136667341@qq.com
3. meiya@cn-meiya.com
4. wq901200@hotmail.com
5. meiyahr@163.com
6. meiyuan@0757info.com
7. chingpeplo@sina.com
8. tony@erene.com.com
9. melodylu@buynow.com
具体释义入下:
1.163邮箱
提供以@163.com为后缀的免费邮箱,3G空间,支持超大20兆附件,280兆网盘。精准过滤超过98%的垃圾邮件。
2.新浪邮箱
提供以@sina.com为后缀的免费邮箱,容量2G,最大附件15M,支持POP3。
3.雅虎邮箱
提供形如@yahoo.com.cn的免费电子邮箱,容量3.5G,最大附件20m,支持21种文字。
4.搜狐邮箱
提供以@sohu.com结尾的免费邮箱服务,提供4G超大空间,支持单个超大10M附件。强大的反垃圾邮件系统为您过滤近98%的垃圾邮件。
5.QQ邮箱
提供以@qq.com为后缀的免费邮箱,容量无限大,最大附件50M,支持POP3,提供安全模式,内置WebQQ、阅读空间等。
"""
# 1. 找出可能是邮箱地址的, 返回一个列表;
pattern = r'\w{6,18}@\w+\.com'
email_li = re.findall(pattern, s)
# 2. 筛选出以字母开头的;
li = []
for email in email_li:
li.append(re.findall(r'^[a-zA-Z].*', email))
# 将嵌套列表转换为非嵌套列表;
print(list(chain(*li)))
这里需要说的是:chain
chain链接可遍历对象(iter1, iter2, ..., iterN)
给出一组迭代器(iter1, iter2, ..., iterN),此函数创建一个新迭代器来将所有的迭代器链接起来,返回的迭代器从iter1开始生成项,知道iter1被用完,然后从iter2生成项,这一过程会持续到iterN中所有的项都被用完。
from itertools import chain
test = chain('AB', 'CDE', 'F')
for el in test:
print(el)
在这里我们只要是将嵌套列表转化为非嵌套列表,就像下面这样的: