前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python正则表达式与re模块-02

python正则表达式与re模块-02

作者头像
suwanbin
发布2019-09-26 10:02:21
5990
发布2019-09-26 10:02:21
举报

正则表达式

正则表达式与python的关系

# 正则表达式不是Python独有的,它是一门独立的技术,所有的编程语言都可以使用正则
# 但要在python中使用正则表达式,就必须依赖于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('18') \
            or phone_number.startswith('19')):
        print('是合法的手机号码')
    else:
        print('不是合法的手机号码')
import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18|19)[0-9]{9}$', phone_number):
    print('是合法的手机号码')
else:
    print('不是合法的手机号码')

从上面两段代码中很容易就可以看得出来,使用正则表达式来校验手机号明显要比纯python 代码来的精简得多。

下面就正式介绍一下正则表达式的一些基本知识

正则表达式

正则表达式: # 一种匹配字符串的规则

官方定义: # 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

常见的应用场景: # 爬虫 , # 数据分析

如果你想系统的学习,可以去了解一下《正则指引》这本书

在开始讲正则语法之前,先推荐大家一个验证正则的网站,可以在线测试你的正则表达式能否满足你的预期效果:正则表达式在线测试 ,大家可以边学习边在该网站上面验证

你改变正则表达式或者下方的待处理字符串他会自动重新匹配

字符组

# 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示

常见的字符组(一个字符组中的数据都是 '或' 的关系)

注意: # 字符组可以用 '-' 表示范围要按照ASCII码表的顺序书写,可以 0-9 不可以 9-0,9的ASCII值比0大

字符

常见元字符(推荐按不同颜色来分组记)

注意: # ^ 与 & 会精准限制匹配的内容,两者中间写什么,待匹配的字符串就必须是什么,多一个少一个都不行 , # 运用 | (“或”)的时候一定要把长的写在前面,否则匹配到短的就匹配完成了,会有很多被截断的

分组(): # 当多个正则符号需要重复多次的时候,或者当做一个整体,进行其他操作,那么可以用分组的形式,分组在正则的语法中就是一个小括号 '(表达式)' ,里面放表达式即可

转义字符

观察上面的元字符可以发现其中有  \n \t 等代表特殊含义的元字符,如果就是要匹配一个字符串 '\n',则会与元字符冲突,故需要在 '\' 前面再加上一个 '\',来防止转义,即要表示字符串 '\n' 正则中需要写成 '\\n'

量词

只能跟在元字符/字符组/正则组后面,限制其左边紧挨着的那个正则表达式(元字符/字符组/正则组),不可两个量词连在一起(除了 '?',解除正则的贪婪模式)

*、+、? 推荐如图所示的画坐标系的方式记忆

贪婪匹配与非贪婪匹配(惰性匹配)

贪婪匹配: # 在满足匹配时,匹配尽可能长的字符串

非贪婪匹配: # 在满足匹配时,匹配尽可能短的字符串

python的匹配模式默认为贪婪匹配,在量词后面加上 ? 可以将其匹配模式改为非贪婪模式,会匹配尽量少的字符串(仅量词作用的那个对象会受影响)

贪婪匹配原理个人理解: # 先匹配到目标字符串 '<',然后直接读取到后面所有的字符串,从倒数第一个字符开始往回找,找到 '>',则将前面的那个位置至这个位置之间的数据返回 ,注意这里是 .* 任意字符 无限多次!!!

非贪婪原理个人理解: # 先匹配到目标字符串 '<',从该位置开始往后寻找字符 '>',找到则这对数据为一个匹配返回结果 ,注意这里是 .* 任意字符 无限多次!!!

案例练习

推荐案例 正则表达式练习题 ,可以根据案例巩固知识

如果你看了本文觉得描述不清,可以参考 re模块 这篇博客,亦或是下图的出处的博客  python正则表达式指南 (前者的博客页面排版看着美观一些,但大部分数据均来源于后者)

python 中的re模块

上面只是介绍了正则表达式的一些基础知识,它是一门独立的技术,要想在python中使用正则表达式,自然就需要通过学习python内置的re模块了(也可以通过其他的一些函数方法等方式使用正则)

要使用 re模块,请不要忘记先导模块(import re)

本文此部分的参考性可能不高,内容也不是很全面,仅作为个人小结,如果有兴趣可以参考 re模块 里面有更详细的讲解以及丰富的案例(另:本模块知识很少用到,所以仅做笔记翻阅)

常见重点函数 findall 找出字符串所有符合内容成一个列表   search 查找匹配结果  match 从开头开始比对

import re

'''
findall  所有符合正则表达式的所有内容
search  有没有符合正则表达式的内容
match   是不是正则表达式对应的开头
'''
# findall 找出字符串中符合正则表达式的所有内容,并且返回一个列表,列表中的元素就是正则表达式匹配到的结果
res = re.findall('[a-z]+', 'nice toZmeet you')
print(res)
# ['nice', 'to', 'meet', 'you']

# search  不会直接返回匹配到的结果,而是给你返回一个对象,这个对象需要调用,通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
# 注意:1.search 只会依据正则查找一次,只要查到了结果,就不会往后查找了
#       2.当查找的结果不存在的情况下,调用group会直接报错
res = re.search('ou', 'nice toZmeet you')
res2 = res.group()  # 必须调用group 才能看到匹配到的结果
print(res, res2)
# <_sre.SRE_Match object; span=(14, 16), match='ou'> ou
res1 = re.search(r'\.', 'nice toZmeet you')
print(res1)
# None
# print(res1.group())  # 直接报错,if空避免


# match
# 注意:1.match 只会匹配字符串的开头部分
#       2.当字符串的开头与正则表达式不符合匹配规则的情况下,返回的也是None,调用 .group 也会报错
res = re.match('s', 'sda e rf a f')
print(res)
# <_sre.SRE_Match object; span=(0, 1), match='s'>
print(res.group())
# s

'''
正则表达式,返回类型为表达式对象的,如:<_sre.SRE_Match object; span=(6, 7), match='a'>,返回对象时,需要用正则方法取字符串,方法有:
    group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2
    groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
    groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
'''

不常用函数 split 切割   sub 替换  compile 将正则编译成一个对象,可对象. 调用上述方法  finditer 返回一个放返回结果的迭代器

import re

# split 类似于字符串的切割split,返回一个列表(他会把被替换掉的字符变成空格)
res = re.split('[ab]', 'sabcasbdsafafabfas')
print(res)
# ['s', '', 'c', 's', 'ds', 'f', 'f', '', 'f', 's']

# sub 类似于字符串的replace 方法,返回替换完成的字符串,可指定替换次数
# sub('正则表达式', '新的内容', '带匹配的字符串', [要替换的次数])
#   先按正则表达式查找所有符合该表达式的内容,统一替换成'新的内容',还可以通过n来控制替换的个数
ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)  # 将数字替换成'H',参数1表示只替换1个
print(ret)
# evaHegon4yuan4

# subn() 字符串replace的加强版,返回替换完成的字符串与总共替换的次数(封成了一个元组)
#   返回的是一个元组,元组的第一个元素是替换完成后的结果,第二个元素代表的是替换的个数
ret = re.subn('\d', 'H', 'eva3egon4yuan4')  # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)
# ('evaHegonHyuanH', 3)


# compile  将正则编译成一个对象,后期可以直接用它来调用 findall、search 等方法
obj = re.compile('\d{3}')  # 将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee')  # 正则表达式对象调用search,参数为待匹配的字符串
print(ret.group())
# 123


# finditer 返回一个存放匹配结果的迭代器,可以使用前面学习到的 迭代器对象.__next__() 方法调用 ---> 简写 next(迭代器对象)
ret = re.finditer('\d', 'ds3sy4784a')
print(ret)
# <callable_iterator object at 0x000001AE62617160>
print(next(ret).group())  # 查看第一个结果
# 3
print(next(ret).group())  # 查看第二个结果
# 4
print([i.group() for i in ret])  # 查看剩余的左右结果
# ['7', '8', '4']

扩展

各方法分组的区别

import re

res = re.search('^[1-9]\d{14}(\d{2}[0-9x])?$', '110105199812067023')
print(res.group())
# 110105199812067023
print(res.group(1))  # 获取正则表达式括号阔起来分组的内容
# 023
# print(res.group(2))  # 报错,取不到     search与match均支持获取分组内容的操作  跟正则无关是python机制

# 而针对findall它没有group取值的方法,所以它默认就是分组优先获取的结果
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
# ['oldboy']

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']

爬虫小案例

'''
本爬虫案例思路:
    分析 https://movie.douban.com/top250?start=%0&filter= 页面得知,每页有25条数据
    通过分次请求该地址,将返回的HTML代码通过正则匹配,解析成想要的字符串格式,
    分页分条存入文件中去(用到了 分组 和 取别名 的知识点)
'''
import re
from urllib.request import urlopen


def getPage(url):
    response = urlopen(url)
    return response.read().decode('utf-8')


def parsePage(s):
    com = re.compile(
        '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
        '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)

    ret = com.finditer(s)
    for i in ret:
        yield {
            "id": i.group("id"),
            "title": i.group("title"),
            "rating_num": i.group("rating_num"),
            "comment_num": i.group("comment_num"),
        }


def main(num):
    url = 'https://movie.douban.com/top250?start=%s&filter=' % num
    response_html = getPage(url)
    ret = parsePage(response_html)
    print(ret)
    f = open("move_info7.txt", "a", encoding="utf8")

    for obj in ret:
        print(obj)
        data = str(obj)
        f.write(data + "\n")


count = 0
for i in range(10):
    main(count)
    count += 25

数据小样

上面仅仅只是一个简单的爬虫案例,如果你想成为一名爬虫工程师,那么你必须的能够熟练地写出正则表达式,言下之意就是除了本文的内容,你还需要好好去学学正则表达式的内容

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-07-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正则表达式
    • 正则表达式与python的关系
      • 正则表达式
        • 字符组
        • 字符
        • 转义字符
        • 量词
        • 贪婪匹配与非贪婪匹配(惰性匹配)
        • 案例练习
        • 扩展
        • 爬虫小案例
    • python 中的re模块
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档