七、正则表达式

在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块,名字为re

re模块的使用过程

#coding=utf-8
# 导入re模块
import re

# 使用match方法进行匹配操作
result = re.match(正则表达式,要匹配的字符串)

# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()

例如要从“hello world” 中查找hello, 可以这样处理:

# encoding=utf-8
import re


def main():
    result = re.match("hello", "hello world")
    print(result.group()) # hello


if __name__ == "__main__":
    main()

re.match() 能够匹配出以xxx开头的字符串

匹配单个字符

字符功能
.匹配任意1个字符(除了\n)
[]匹配[]中列举的字符
\d匹配数字,即0-9
\D匹配非数字,即不是数字
\s匹配空白,即空格,tab键
\S匹配非空白
\w匹配单词字符,即a-z,A-Z,0-9,_

(1) 匹配任意1个字符

# encoding=utf-8
import re


def main():
    ret = re.match(".", "M")
    print(ret.group())

    ret = re.match("t.o", "toooo")
    print(ret.group())

    ret = re.match("t.o", "two")
    print(ret.group())


if __name__ == "__main__":
    main()

输出结果:

M
too
two

(2)匹配 [] 内的字符

# encoding=utf-8
import re


def main():
    # 如果hello的首字符小写,那么正则表达式需要小写的h
    ret = re.match("h", "hello Python")
    print(ret.group())  # 结果:h

    # 如果hello的首字符大写,那么正则表达式需要大写的H
    ret = re.match("H", "Hello Python")
    print(ret.group())  # 结果:H

    # 大小写h都可以的情况
    ret = re.match("[hH]", "hello Python")
    print(ret.group())  # 结果:h
    ret = re.match("[hH]", "Hello Python")
    print(ret.group())  # 结果:H
    ret = re.match("[hH]ello Python", "Hello Python")  # 结果:Hello Python
    print(ret.group())

    # 匹配0到9的第一种写法
    ret = re.match("[0123456789]hello python", "7hello python")  # 结果:7hello python
    print(ret.group())

    # 匹配0到9第二种写法
    ret = re.match("[0-9]Hello Python", "7Hello Python")  # 结果:7hello python
    print(ret.group())

    ret = re.match("[0-35-9]Hello Python", "7Hello Python")  # 结果:7hello python
    print(ret.group())

    # 下面这个正则不能够匹配到数字4,因此ret为None
    ret = re.match("[0-35-9]Hello Python", "4Hello Python")
    # print(ret.group()) 会报错


if __name__ == "__main__":
    main()

(3)\d匹配数字

# encoding=utf-8
import re


def main():
    ret = re.match("aa\dbb", "aa2bb")
    print(ret.group())  # 结果:aa2bb


if __name__ == "__main__":
    main()

(4) \D匹配非数字

# encoding=utf-8
import re


def main():
    ret = re.match("12\D34", "12a34")
    print(ret.group())  # 结果:12a34


if __name__ == "__main__":
    main()

(5)\s匹配空白字符

# encoding=utf-8
import re


def main():
    ret = re.match("12\s34", "12 34")
    print(ret.group())  # 结果:12 34


if __name__ == "__main__":
    main()

(6)\S 匹配非空白字符

# encoding=utf-8
import re


def main():
    ret = re.match("\S34", "a34")
    print(ret.group())  # 结果:a34


if __name__ == "__main__":
    main()

(7)\w匹配单词字符

# encoding=utf-8
import re


def main():
    ret = re.match("\w", "world 123")
    print(ret.group())  # 结果:w


if __name__ == "__main__":
    main()

(8)\W匹配非单词

# encoding=utf-8
import re


def main():
    ret = re.match("\W", "$hello")
    print(ret.group())  # 结果:$


if __name__ == "__main__":
    main()

数量匹配符

匹配多个字符的相关格式

字符功能
*匹配前一个字符,出现0次或者无限次,即可有可无
+匹配前一个字符出现1次或者无限次,即至少有一次
?匹配前一个字符出现1次或者0次,即最多有一次
{m}匹配前一个字符出现m次
{m,n}匹配前一个字符出现从m到n次

(1)*匹配符

# encoding=utf-8
import re


def main():
    # 匹配大写字母开头,后面有0个或多个小写字母
    ret = re.match("[A-Z][a-z]*", "Hello World")
    print(ret.group())  # 结果:Hello


if __name__ == "__main__":
    main()

(2)+匹配符

# coding=utf-8
import re

names = ["name1", "_name", "2_name", "__name__"]

for name in names:
    # 匹配字母或者下划线开头的次数出现1次或多次,后面出现0次或多次个字符
    ret = re.match("[a-zA-Z_]+[\w]*", name)
    if ret:
        print("变量名 %s 符合要求" % ret.group())
    else:
        print("变量名 %s 非法" % name)

输出结果:

变量名 name1 符合要求
变量名 _name 符合要求
变量名 2_name 非法
变量名 __name__ 符合要求

(3)?匹配符

# coding=utf-8
import re


def main():
    # 匹配出,0到99之间的数字
    ret = re.match("[1-9]?[0-9]", "75")
    print(ret.group()) # 75

    ret = re.match("[1-9]?\d", "33")
    print(ret.group()) # 33

    ret = re.match("[1-9]?\d", "09")
    print(ret.group()) # 0
 

if __name__ == '__main__':
    main()


## (4) {m},次数限定匹配符

```python
# coding=utf-8
import re

# 匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线
ret = re.match("[a-zA-Z0-9_]{6}", "12a3g45678")
print(ret.group()) # 12a3g4

ret = re.match("[a-zA-Z0-9_]{8,20}", "1ad12f23s34455ff66")
print(ret.group()) # 小于8个字符会报错, 1ad12f23s34455ff66
# 上面的[a-zA-Z0-9_]其实也可以用\w来替代

匹配开头结尾

字符功能
^匹配字符串开头
$匹配字符串结尾

(1) 匹配数字开头的字符串

# coding=utf-8
import re

ret = re.match("^\d*", "1232456aaaaa")
print(ret.group()) # 结果:1232456

(2) 匹配@163.com结尾的字符串

# coding=utf-8
import re

email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]

for email in email_list:
    ret = re.match("\w*@163.com$", email)
    if ret:
        print("匹配成功的是:%s" % ret.group())
    else:
        print("匹配失败的是:%s" % email)

输出结果:

匹配成功的是:xiaoWang@163.com
匹配失败的是:xiaoWang@163.comheihei
匹配失败的是:.com.xiaowang@qq.com

匹配分组

字符功能
|匹配左右任意一个表达式
(ab)将括号中字符作为一个分组
\num引用分组匹配到的字符串
(?p)分组起别名
(?P=name)引用别名name分组匹配的字符串

(1)或匹配符|

# coding=utf-8
import re

ret = re.match("[1-9]?\d$|100", "100")
print(ret.group())  # 100

ret = re.match("[1-9]?\d$|100", "20")
print(ret.group())  # 20

(2)分组匹配符()

# coding=utf-8
import re

email_list = ["abc@126.com", "hello@163.com", "xxx@qq.com"]

for email in email_list:
    ret = re.match("\w+@(163|126|qq)\.com$", email)
    print(ret.group())

输出结果:

abc@126.com
hello@163.com
xxx@qq.com

(3)引用分组匹配\

例如要匹配形如出hh格式的字符串, 你可能会想到下面的方式:

# coding=utf-8

import re

# 能够完成对正确的字符串的匹配
ret = re.match("<[a-zA-Z]+>\w*</[a-zA-Z]+>", "<html>hh</html>")
print(ret.group())

输出结果:

<html>hh</html>

但是这种还会匹配出错误的结果,例如这种hh,按理说后面的<>要和前面的内容一样,这个时候就可以引用分组,引用分组的格式是:\分组的数字,同时还需要在正则表达式前加上r,分组的部分需要用()括起来,而\1对于的就是分组1,以此类推,例如:

# coding=utf-8

import re

# 能够完成对正确的字符串的匹配
ret = re.match(r"<([a-zA-Z]+)>\w*</\1>", "<html>hh</html>")
print(ret.group())

(4) 分组起别名和同别名引用分组

以匹配出<html><h1>www.163.com</h1></html>为例

# coding=utf-8

import re

# 能够完成对正确的字符串的匹配
ret = re.match(r"<(?P<group1>\w+)><(?P<group2>\w+)>.*</(?P=group2)></(?P=group1)>",
               "<html><h1>www.163.com</h1></html>")
print(ret.group())

注意:(?P)和(?P=name)中的字母p大写

他们的引用关系如下:
在这里插入图片描述

re的高级用法

(1)search的使用

# coding=utf-8
import re

# 匹配出文章阅读的次数
# 匹配出文章阅读的次数
ret = re.search(r"\d+", "阅读次数为 9999  点赞数 10")
print(ret.group()) # 9999

(2)findall查找多个

# coding=utf-8
import re

# 统计出python、c、c++相应文章阅读的次数
ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret) # ['9999', '7890', '12345']

(3)sub将匹配到的数据进行替换

# coding=utf-8
import re

# 将python = 997中的977替换成100
ret = re.sub(r"\d+", '100', "python = 997")
print(ret) # 结果:python = 100

例如要提取网页的内容,非标签字符可以这样处理:

# coding=utf-8
import re

test_str = """
<div>
        <p>岗位职责:</p>
        <p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
        <p><br></p>
        <p>必备要求:</p>
        <p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
        <p>&nbsp;<br></p>
        <p>技术要求:</p>
        <p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
        <p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
        <p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
        <p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
        <p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
        <p>&nbsp;<br></p>
        <p>加分项:</p>
        <p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
</div>
"""

ret = re.sub(r"<[^>]*>|&nbsp;|", "", test_str)
print(ret)

思路很简单就是将标签<>或者</>替换成空白字符即可,至于<>的内容可以用[^>]*来表示。

(4)split切割字符串

# coding=utf-8
import re

# 如果想按:分割字符串,可以这样
ret = re.split(r":", "info:xiaoZhang 33 shandong")
print(ret)

# 如果想按:或者空格符分割字符串,可以这样
ret = re.split(r":| ", "info:xiaoZhang 33 shandong")
# 上面这句还可以改成:ret = re.split(r":|\s", "info:xiaoZhang 33 shandong")
print(ret)

输出结果:

['info', 'xiaoZhang 33 shandong']
['info', 'xiaoZhang', '33', 'shandong']

贪婪和非贪婪匹配

Python里数量词默认是贪婪的也就是尝试匹配尽可能多的字符;
而非贪婪则相反,总是尝试匹配尽可能少的字符。
在"*“,”?“,”+“,”{m,n}"后面加上?,使贪婪变成非贪婪。

# coding=utf-8
import re

# 贪婪模式(默认),尽可能匹配的多点
s = "This is a number 234-235-22-423"
r = re.match(".+(\d+-\d+-\d+-\d+)", s)
print(r.group())  # This is a number 234-235-22-423
print(r.group(1))  # 4-235-22-423, 这里group(1) 可以获取第一个()内的内容

# 非贪婪模式,尽可能匹配的少点
r = re.match(".+?(\d+-\d+-\d+-\d+)", s)
print(r.group())  # This is a number 234-235-22-423
print(r.group(1))  # 234-235-22-423

输出结果:

This is a number 234-235-22-423
4-235-22-423
This is a number 234-235-22-423
234-235-22-423

group方法可以传入分组的编号,这样就可以取对应分组的内容了,如果不传则取所有内容

再入可以配合findall或者search来提取特定字符串,例如提取网页中的url

# coding=utf-8
import re

test_str = """
<img data-original="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg" 
    src="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg"
     style="display: inline;">"
"""

# 如何提取url

ret = re.findall(r"https://.*?\.jpg", test_str)
print(ret)

输出结果:

['https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg', 'https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg']
Python中字符串前面加上 r 表示原生字符串
与大多数编程语言相同,正则表达式里使用`\`作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符`\`,那么使用编程语言表示的正则表达式里将需要2个反斜杠,即`\\`. 而Python里的原生字符串很好地解决了这个问题,有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

例如:

# coding=utf-8
import re

# 没有使用原生字符串的使用
test_str = "c:\\a\\b\\c"
ret = re.match("c:\\\\a", test_str).group()
print(ret)  # c:\a

# 使用了原生字符串的使用
test_str = r"c:\a\b\c"
# 正则表达式里面只需要对\进行一次转义即可
ret = re.match(r"c:\\a", test_str).group()
print(ret)  # c:\a

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值