常用模块-正则re

常用模块之正则模块

"""
正则表达式与re模块的关系
    1.正则表达式是一门独立的技术,任何语言均可使用
    2.python中要想使用正则表达式需要通过re模块
"""

初识正则表达式

网站手机号校验功能示例:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/

有无正则校验的区别

# 纯python代码校验
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(‘18‘)):
        print(‘是合法的手机号码‘)
    else:
        print(‘不是合法的手机号码‘)
      
      
# 正则表达式校验
import re
phone_number = input(‘please input your phone number : ‘)
if re.match(‘^(13|14|15|18)[0-9]{9}$‘,phone_number):
        print(‘是合法的手机号码‘)
else:
        print(‘不是合法的手机号码‘)
# 正则在所有语言中都可以使用 不是python独有的
# 匹配大段文本中特定的字符

正则表达式在线测试

与re模块没有任何关系,仅仅是测试正则表达式:http://tool.chinaz.com/regex/

测试匹配手机号

正则表达式应用场景

  • 爬虫

  • 数据分析

推荐书籍:正则指引

字符组概念

在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示(一个字符组每次只能匹配一个字符)

小例子

  • 匹配0-9数字([0123456789]也支持简写[0-9])(如果想匹配横杠,转义即可)

  • 匹配A-Z字母(依据上面的简写规则[A-Z])

  • 匹配a-z字母(依据上面的简写规则[a-z])

ps:这种上面到上面的范围必须是从小到大[a-Z]不行,[A-z]可以(但是内部有几个特殊符号),因为内部对应的asicc码A在所有字母里面最小,z在所有字母里面最大

正则表达式符号介绍

按照博客中的表格罗列的去记即可

了解

\w,\s,\d与\W,\S,\D相反的匹配关系(对应的两者结合就是匹配全局)
\t匹配制表符
\b匹配结尾的指定单词

优先掌握

  • ^:以什么什么开头

    • ^[a-z]

    • ^[0-9]

  • $:以什么什么结尾

ps:^与$连用能够精准匹配固定长度的目标字符,^只能出现在开头(),$只能出现结尾

  • |:或

    • ab|abc优先匹配前面的正则表达式ab,匹配上就不再用后面的abc,可以通过调换顺序修改优先级

  • ^:出现在[]中的^表示除了^后面的其他都匹配

    • [^a]除了a其他都匹配

    • [^a-z]除了小写字母a-z其他都匹配

上面的是匹配单个字符的符号,接下来需要学习匹配个数的限制符号

量词

  • +:我想要匹配13838384388,\d一次只能匹配到一个数字,要想一次讲号码全部匹配上需要用到\d+,+表示重复一次或者多次,并且正则中默认都是贪婪匹配,越多越好

  • *:匹配0次或多次

  • ?:匹配0次或一次

ps:

1.对于这个0次也能匹配出来的结果,暂时不用考虑

2.*,+,?的工作区间可以用坐标轴的形式表示出来

  • {n}:明确指定个数

注意:量词需要写在匹配符号的后面,并且只约束紧挨着它的那个正则表达式

小例子

  • 逐个匹配出后面的道:轨道 通道 地道 魔道 人道

  • 匹配人名:海燕海娇海东

字符集

分组

  • 一次性匹配a1b2c3

    [a-z][0-9]会匹配到三个结果

    想法:重复写三次,但是太麻烦,加量词的话只能限制离得最近的正则表达式

    这个时候就可以用分组([a-z][0-9])+

  • 匹配身份证号

    依据博客一次分析(下面的正则之所以加^和$是因为我们仅仅只想匹配身份证号,教学演示方便,不加照样也能匹配上,只不过前后可以出现很多其他字符)

    1.^[1-9]\d{13,16}[0-9x]$:不完善的地方在于默认是x的情况只在18位才可能出现,但是这个表达式没有做这一层的限制

    2.^[1-9]\d{14}(\d{2}[0-9x])?$

    3.^([1-9]\d{16}[0-9x]|[1-9]\d{14})$

转义符

在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成‘\‘。

在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。

所以如果匹配一次"\n",字符串中要写成‘\\n‘

所以如果匹配一次"\\n",字符串中要写成‘\\\\n‘

简便操作,利用r可以让整个字符串都不再转义(了解:r其实就是real的意思,真实不转义)

贪婪匹配与非贪婪匹配

  • <.*>:先拿着里面的.*去匹配所有的内容,然后再根据>往回退着找,遇到即停止

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

ps:根据匹配的内部原理可以很好的理解

.*?x就是取前面任意长度的字符,直到一个x出现

至此整个后期项目里面能用到的正则表达式就已经给你讲完了,把这些记住足够你在后面的项目和爬虫中用了

讲了这么久,一点python的事儿都还没扯,现在就要来学在python里面如何使用

re模块使用

三个必须掌握的方法

  • findall

  • search

  • match

import re
?
# 第一个参数是正则表达式,第二个参数是待匹配的文本内容
?
ret = re.findall(‘a‘, ‘eva egon yuan‘)  # 返回所有满足匹配条件的结果,放在列表里
print(ret)
?
ret = re.search(‘a‘, ‘eva egon yuan‘)  
print(ret.group())  # 结果:‘a‘
# 函数会在字符串内查找模式匹配,直到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None,并且需要注意的是如果ret是None,再调用.group()会直接报错。这一易错点可以通过if判断来进行筛选
if ret:
    print(ret.group())
?
ret = re.match(‘a‘, ‘abc‘).group()  # 同search,不过仅在字符串开始处进行匹配
print(ret)  # ‘a‘
# match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个对象,需要用group才能显示,如果没匹配上就返回None,调用group()就会报错

其他方法

ret = re.split(‘[ab]‘, ‘abcd‘)  # 先按‘a‘分割得到‘‘和‘bcd‘,在对‘‘和‘bcd‘分别按‘b‘分割
print(ret)  # [‘‘, ‘‘, ‘cd‘]
?
ret = re.sub(‘\d‘, ‘H‘, ‘eva3egon4yuan4‘, 1)  # 将数字替换成‘H‘,参数1表示只替换1个
print(ret)  # evaHegon4yuan4
?
ret = re.subn(‘\d‘, ‘H‘, ‘eva3egon4yuan4‘)  # 将数字替换成‘H‘,返回元组(替换的结果,替换了多少次)
print(ret)
?
obj = re.compile(‘\d{3}‘)  #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search(‘abc123eeee‘) #正则表达式对象调用search,参数为待匹配的字符串
print(ret.group())  #结果 : 123
?
import re
ret = re.finditer(‘\d‘, ‘ds3sy4784a‘)   #finditer返回一个存放匹配结果的迭代器
print(ret)  # <callable_iterator object at 0x10195f940>
print(next(ret).group())  #查看第一个结果
print(next(ret).group())  #查看第二个结果
print([i.group() for i in ret])  #查看剩余的左右结果

扩展

分组优先机制

import re
res = re.search(‘^[1-9]\d{14}(\d{2}[0-9x])?$‘,110105199812067023)
print(res.group())
print(res.group(1))  # 获取正则表达式括号阔起来分组的内容
print(res.group(2))  # search与match均支持获取分组内容的操作  跟正则无关是python机制
?
# 而针对findall它没有group取值的方法,所以它默认就是分组优先获取的结果
ret = re.findall(‘www.(baidu|oldboy).com‘, ‘www.oldboy.com‘)
print(ret)  # [‘oldboy‘]     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
?
ret = re.findall(‘www.(?:baidu|oldboy).com‘, ‘www.oldboy.com‘)  # ?:取消分组优先
print(ret)  # [‘www.oldboy.com‘]

补充

import re
?
?
ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
#还可以在分组中利用?<name>的形式给分组起名字
#获取的匹配结果可以直接用group(‘名字‘)拿到对应的值
print(ret.group(‘tag_name‘))  #结果 :h1
print(ret.group())  #结果 :<h1>hello</h1>
"""
注意?P=tag_name相当于引用之前正则表达式,并且匹配到的值必须和前面的正则表达式一模一样
"""
?
# 匹配整数
ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) #[‘1‘, ‘2‘, ‘60‘, ‘40‘, ‘35‘, ‘5‘, ‘4‘, ‘3‘]
?
ret=re.findall(r"\d+\.\d*|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) #[‘1‘, ‘2‘, ‘60‘, ‘‘, ‘5‘, ‘4‘, ‘3‘]
ret.remove("")
print(ret) #[‘1‘, ‘2‘, ‘60‘, ‘5‘, ‘4‘, ‘3‘]

相关推荐