判断一个字符串是否是合法的Email地址
上面的需求虽然可以通过提取@字符、分别判断@前后的单词和域名来达到目的,但是这种做不仅繁琐,而且代码难以复用
正则表达式的设计思想是使用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,就会被认定为匹配,反之就是不匹配。而上述情况就可以使用正则表达式来进行匹配字符串,从而达到目的,并且可以进行复用。
使用正则表达式对上述需求进行操作的步骤是:
- 创建一个匹配Email的正则表达式
- 使用正则表达式匹配输入的字符串是否匹配
==(1)==在正则表达式中,如果直接给出字符,就是
精确匹配,使用\d可以匹配一个数字,使用\w可以匹配一个字母或者数字,例如:
00\d:可以匹配以00开头,以数字结尾,比如007、004等,但是无法匹配00A、00v这种的\d\d\d:可以匹配三个任意数字,比如123、543等\w\w\d:可以匹配前两位以字母或数字开头,以数字结尾,比如a33、cc3、4f1等==(2)==使用
.可以匹配任意字符,例如:
py.:可以匹配以py开头,以任意字符结尾,比如py4、pya、py-等==(3)==想要匹配变长的字符,可以使用
*表示匹配任意字符,包括0个字符,使用+表示至少1个字符,使用?表示0或1个字符,使用{n,m}表示n到m个字符,下面来看案例:
\d{3}\s+\d{3,8}:从左到右分析,\d{3}匹配3个数字,比如123这样,\s可以匹配一个空格,包括TAB等空白符,而\s+就表示匹配至少一个空格,例如' '、' '等,\d{3,8}表示匹配3到8个数字,表示数字的数量最少是3,最大是8,比如123456、123、12345678这样。通过这个正则表达式,可以匹配带区号的电话号码==(4)==想要更加精确的匹配字符,可以使用
[]表示范围:
[0-9a-zA-Z\_]:可以匹配一个数字、字母或者一个下划线
[0-9a-z-A-Z\_]+:可以匹配至少由1个数字、字母或下划线组成的字符串,匹配数量大于1
[a-zA-Z\_][0-9a-zA-Z\_]*:可以匹配由一个字母或下划线开头,然后接任意数量的由数字、字母、下划线组成的字符串
[a-zA-Z\_][0-9a-zA-Z\_]{0,19}:和上面的匹配规则相同,只是限制了字符的长度==(5)==还有其他的特殊字符例如:
|:表示或的意思,比如A|B,可以匹配A或者B
^:表示开头,比如^A,就是匹配以A开头的
$:表示末尾,比如A$,就是匹配以A结尾的
如果不使用特殊字符,只是单纯的字符串的话,那么相当于是
包含的意思,例如,正则表达式为py,而字符串第一行为python第二行为py,使用正则表达式会全部进行匹配,即两行字符串都会进行匹配,如果正则表达式为^py$,那么正则表达式就只会匹配第二行的py了
re模块,其中包含了所有正则表达式的功能\转义的,而使用r前缀就无需考虑转义问题,例如:- 通过 \ 进行转义
>>> s = 'ABC\\-001'
>>> print(s)
ABC\-001
- 使用 r 进行转义
>>> s = r'ABC\-001'
>>> print(s)
ABC\-001
使用
match()方法判断是否匹配,如果匹配成功会返回一个Match对象,反之返回None
match():第一个参数是正则表达式,第二个参数是要匹配的字符串
>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$','010-12345')
<re.Match object; span=(0, 9), match='010-12345'> #匹配成功返回match对象
>>> re.match(r'^\d{3}\-\d{3,8}$','010 12345')
>>> a = re.match(r'^\d{3}\-\d{3,8}$','010 12345')
>>> print(a)
None #匹配不成功,返回None
test = '字符串'
if re.match(r'正则表达式',test):
print('ok')
else:
print('failed')
>>> 'ab c'.split(' ')
['ab', '', '', '', 'c'] #可以看到无法识别连续的空格
>>> re.split(r'\s+','ab c')
['ab', 'c'] #可以看到相同的字符串可以正常分割
>>> re.split(r'[\s\,]+','a,b, c d') #加入 , 进行分割
['a', 'b', 'c', 'd']
>>> re.split(r'[\s\,\:]+','a,b:::, c d') #加入 : 进行分割
['a', 'b', 'c', 'd']
子串的强大功能,使用()表示的就是要提取的分组Group,例如:
^(\d{3})-(\d{3,8})$:这个正则表达式定义了两个分组,可以直接从匹配的字符串中提取出区号和本地号码
>>> m = re.match(r'^(\d{3})-(\d{3,8})$','010-12345')
>>> m
<re.Match object; span=(0, 9), match='010-12345'>
- 如果在正则表达式中定义了组,就可以在match对象上使用group()方法提取出子串来,例如:
>>> m.group(0) #group(0)永远是整个匹配的字符串
'010-12345'
>>> m.group(1) #后续的1、2、3...就代表着第1、2、3...个子串
'010'
>>> m.group(2)
>>> t = '22:33:44'
>>> m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t)
>>> m.group(0)
'22:33:44'
>>> m.group(1)
'22'
>>> m.group(2)
'33'
>>> m.group(3)
'44'
2-30、4-31这样的非法日期还是无能为力,或者是写出来非常困难,这时就需要程序配合识别了- 匹配出数字后面的0
>>> re.match(r'^(\d+)(0*)$','102300').groups()
('102300', '')
\d+组采用贪婪匹配,直接把后面的0全部匹配了,结果0*组只能匹配空字符串了\d+采用非贪婪匹配,可以加个?即可:>>> re.match(r'^(\d+?)(0*)$','102300').groups()
('1023', '00')
- 可以看到加了 ? 后,0* 组也匹配了字符串
- 编译正则表达式,如果正则表达式的字符串本身语法不正确,那么就会报错
- 使用编译后的正则表达式去匹配字符串
>>> import re
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-80808').groups()
('010', '80808')
# -*- coding: utf-8 -*-
from http.client import FAILED_DEPENDENCY
import re
def is_valid_email(addr):
if re.match(r'^(\w+(\.)?\w+)@(\w+)(.com){1}$', addr):
print("ok")
return True
else:
print("faild")
return False
# 测试:
assert is_valid_email('someone@gmail.com')
assert is_valid_email('bill.gates@microsoft.com')
assert not is_valid_email('bob#example.com')
assert not is_valid_email('mr-bob@example.com')
print('ok')
- 执行
ok
ok
faild
faild
ok
# -*- coding: utf-8 -*-
from http.client import FAILED_DEPENDENCY
import re
def name_of_email(addr):
res = re.match(r'^(\w+\s?\w+)>?\s?(\w){0,}@(\w+\.\w+)', addr)
if res:
print(res.groups()) # 根据正则表达式括号部分分组
return res.group(1)
else:
return False
# 测试:
assert name_of_email(' tom@voyager.org' ) == 'Tom Paris'
assert name_of_email('tom@voyager.org') == 'tom'
print('ok')
- 执行
('Tom Paris', 'm', 'voyager.org')
('tom', None, 'voyager.org')
ok