importlib解析(**) | 正则表达式与Re模块

今日内容


 

昨日内容补充:


 

对于两个文件中的互相导入md模块问题分析:

x = 1

from md import x

    print(x)

# md中的x


from md import x

    x = 1000

    print(x)

# 当前文件中的x

__all__ 列表写什么,执行导入语句那个文件就能拿到什么;

__all__不写的情况,默认是将所在文件所有的名字都暴露给导入者.

解决循环导入的第三种方式(前两种已在day14涉及):

  • 将循环导入的名字,放到另外一个文件中

 

正则表达式


定义: 正则就是用来筛选字符串中的特定的内容的,对字符串进行操作的逻辑工具

re模块与正则表达式之间的关系:

  • 正则表达式不是python独有的,它是一门独立技术
  • 所有的编程语言都可以用正则
  • 如果想在python中用,就必须依赖于re模块

相关书籍: <正则指引>

验证工具: www.tool.chinaz.com

正则的应用场景:

  • 1.爬虫
  • 2.数据分析

 注意点: 只要是reg...一般情况下都是跟正则有关,而且如果想匹配具体的内容,可以直接写完整的内容,不需要写正则

 

字符组[ ]:

正则
待匹配字符
 
 匹配结果
说明
 
[0123456789]
 8  
True
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符
和"待匹配字符"相同都视为可以匹配
 
[0123456789]
 a  
False
 
由于字符组中没有"a"字符,所以不能匹配
 
[0-9]
 7  
True
 
也可以用-表示范围,[0-9]就和[0123456789]是一个意思
 
[a-z]
 s  
True
 
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
 
[A-Z]
 B  
True
 
[A-Z]就表示所有的大写字母
 
[0-9a-fA-F]
 e  
True
 
可以匹配数字,大小写形式的a~f,用来验证十六进制字符

关于字符:

元字符
匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W
匹配非字母或数字或下划线
\D
匹配非数字
\S
匹配非空白符
a|b
匹配字符a或字符b
()
匹配括号内的表达式,也表示一个组
[...]
匹配字符组中的字符
[^...]
匹配除了字符组中字符的所有字符

 

关于量词:

量词
用法说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次


注意点:

  • 通常一个字符组里面的表达式都是或关系
  • \w:\word与\W相反
  • \s:\space与\S相反
  • \d:\digit与\D相反
  • ^匹配字符串的开始 类似于startswith
  • $匹配字符串的结尾 类似于endswith
  • ^如果直接写在外面,就是限制字符串开头的作用
  • [^...]就是取反的意思,除了...之外其他都能输出
  • a|b,如果是abc|ab,一定要将长的放在前面

PS: ^与$连用,就能精准限制匹配的内容,两者之间写什么,匹配的字符串就必须是什么,多一个不行,少一个也不行

例如:^jason$,最终输出结果就一定是jason

贪婪匹配Patten与非贪婪匹配:

正则 待匹配字符 匹配结果 说明
<.*>   <script>...<script> <script>...<script>
默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?> r'\d'    <script>
<script>
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
  • <.*>:先拿着里面的.*去匹配所有的内容,然后再根据>往回退着找,遇到即停止

  • <.*?>:先拿着?后面的>去匹配符合条件的最少的内容,然后把匹配的结果返回

PS:根据匹配的内部原理可以很好的理解, .*?x 就是取前面任意长度的字符,直到一个x出现

 

注意点:

  • 正则在匹配的时候默认都是贪婪匹配(尽量匹配多的)
  • 量词必须跟在正则符号后面
  • 量词只能够限制紧挨着它的左侧表达式的那一个正则符号
  • 量词后面加上一个?就可以将贪婪匹配变成非贪婪匹配(惰性匹配)

分组()  或|  [^]:

正则 待匹配字符 匹配结果 说明
^[1-9]\d{13,16}[0-9x]$ 110101198001017032 110101198001017032 表示可以匹配一个正确的身份证号
^[1-9]\d{13,16}[0-9x]$ 1101011980010170 1101011980010170
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字
^[1-9]\d{14}(\d{2}[0-9x])?$ 1101011980010170 False
现在不会匹配错误的身份证号了
()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ 110105199812067023 110105199812067023
表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14}

定义:当多个正则符号需要重复多次时,或者当作一个整体进行其他操作,那么可以分组

分组在正则的语法中就是( )

例如: 用[a-z][0-9]会匹配到三个结果,这个时候就可以用分组([a-z][0-9])+,可以提高不少效率

例题: 关于身份证的正则表达式

  • ^[1-9]\d{13,16}[0-9x]$
  • ^[1-9]\d{14}(\d{2}[0-9x])?$
  • ^([1-9]\d{16}[0-9x]|[1-9]\d{14})$

 上面三种都是解决方法,第三种考虑的最全面

转义符:

正则 待匹配字符 匹配结果 说明
 \n  \n  False
因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\\n  \n    True  
转义\之后变成\\,即可匹配
 '\\\\n'  '\\n'   True  
如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次
 r'\\n'  r'\n'   True  
在字符串之前加r,让整个字符串不转义

注意点:

  • 在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成'\'
  • python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的
  • 字符串中\也有特殊的含义,本身还需要转义
  • 如果匹配一次"\n",字符串中要写成'\\n'
  • 如果匹配一次"\\n",字符串中要写成'\\\\n'
  • r'\\n' 在字符串前面加个r,让整个字符串不转义(了解:r其实就是real的意思,真实不转义)

 

re模块:


 

定义:python中使用正则必须借助于re模块,或者是支持正则表达式书写的功能与方法

 while True:

     phone_number = input('please input your phone number : ')

     if len(phone_number) == 11 \

             and phone_number.isdigit()\

             and (phone_number.startswith('13') \

             or phone_number.startswith('14') \

             or phone_number.startswith('15') \

             or phone_number.startswith('16') \

             or phone_number.startswith('17') \

             or phone_number.startswith('18')):

         print('是合法的手机号码')

     else:

         print('不是合法的手机号码')


 import re

 phone_number = input('please input your phone number : ')

 if re.match('^(13|14|15|16|17|18)[0-9]{9}$',phone_number):

         print('是合法的手机号码')

 else:

         print('不是合法的手机号码')
运用正则表达式+re模块来解决用户以手机号来注册并验证的问题

三种主要方法:

  • findall找出字符串中符合正则表达式的全部内容,并且返回的是一个列表,列表中的元素就是正则匹配到的结果
  • searfch只会依据正则查一次 只要查到了结果,就不会再往后查找;当查找的结果不存在的情况下 调用group直接报错
  • match只会匹配字符串的开头部分;当字符串的开头不符合匹配规则的情况下 返回的也是None 调用group也会报错
ret = re.findall('[a-z]+', 'eva egon jason')

# findall('正则表达式', '带匹配的字符串')

print(ret)  # ['eva', 'egon', 'jason']
findall
ret = re.search('a', 'eva egon jason')

# search('正则表达式', '带匹配的字符串')

print(ret)  # 返回 <_sre.SRE_Match object; span=(2, 3), match='a'> 

# search不会给你直接返回匹配到的结果,而是给你返回一个对象

print(ret.group())  # a

# 必须调用group才能看到匹配到的结果
search(正常选存在的字符)
ret1 = re.search('k', 'eva egon jason')

print(ret1.group())  # 直接报错,因为print(ret)返回None,而且None没有内置group方法
search(选不存在的字符)
ret = re.match('e', 'eva egon jason')

print(ret)  # 返回<_sre.SRE_Match object; span=(0, 1), match='e'> 

print(ret.group())  # e
match(选首位字符)
ret = re.match('a', 'eva egon jason')

print(ret)  #  返回None

print(ret.group())  # 直接报错
match(选非首位字符)

其他方法:

split:分割

ret = re.split('[ab], 'abcd')  # 先按'a'分割得到' ''bcd',再对' ''bcd'分别按'b'分割

print(ret)  # 返回的还是列表[' ', ' ', 'cd']
split

sub:替换,先按照正则表达式查找所有符合该表达式的内容 统一替换成'新的内容' 还可以通过n来控制替换的个数

ret = re.sub('\d', 'H','eva3egon4yuan4',1)  # 将数字替换成'H',参数1表示只替换1个

# sub('正则表达式', '新的内容', '待替换的字符串',n)

print(ret)  # 返回值为evaHegon4yuan4
sub

subn:替换(返回元祖)

ret = re.subn('\d', 'H', 'eva3egon4yuan4')  # 将数字替换成'H',返回元组(替换的结果,替换了多少次)

ret1 = re.subn('\d', 'H', 'eva3egon4yuan4',1)  # 将数字替换成'H',返回元组(替换的结果,替换了多少次)

print(ret)  # 返回的是一个元组 元组的第二个元素代表的是替换的个数
subn

obj:编译(转换功能)

obj = re.compile('\d{3}')  # 将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字

ret = obj.search('abc123eeee')  # 正则表达式对象调用search,参数为待匹配的字符串

ret1 = obj.findall('347982734729349827384')

print(ret.group())  # 返回结果是 123

print(ret1)  # 返回结果是 ['347', '982', '734', '729', '349', '827', '384'] 
obj

finditer:返回一个存放匹配结果的迭代器

ret = re.finditer('\d', 'ds3sy4784a')  # finditer返回一个存放匹配结果的迭代器

print(ret)  # 返回<callable_iterator object at 内存地址>

print(next(ret).group())  # 等价于ret.__next__(),超出迭代取值的范围 直接报错StopIteration

print([i.group() for i in ret])  # 查看剩余的左右结果
finditer

 

扩展知识点:


 

1.?P可以给某一个正则表达式起别名

import re

res = re.search('^[1-9] (\d{14})(\d{2}[0-9x])?$','110105199812067023')

res = re.search('^[1-9] (?P<password>\d{14})(?P<username>\d{2}[0-9x])?$','110105199812067023')

print(res.group())  # 返回值为110105199812067023

print(res.group('password'))  # 返回值为110105199812067

print(res.group(1))  # 返回值为110105199812067

print(res.group('username'))  # 返回值为023

print(res.group(2))  # 返回值为023

2.?:取消权限,findall就不会优先把匹配结果组里内容返回

ret1 = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')

ret2 = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') 

# 忽略分组优先的机制

print(ret1,ret2)  # ['oldboy']

3.关于split的知识点

ret=re.split("\d+","eva3egon4yuan")

print(ret)  # 结果 : ['eva', 'egon', 'yuan']

ret1=re.split("(\d+)","eva3egon4yuan")

print(ret1)  # 结果 : ['eva', '3', 'egon', '4', 'yuan']

 

posted @ 2019-07-17 21:14  泡泡茶壶i  阅读(231)  评论(0)    收藏  举报