python 正则表达式

正则表达式概述

思考

场景1:在一个文件中,查找出itcast开头的语句

测试文件


  
  
  1. itcast hello python
  2. itcast c++
  3. itheima ios
  4. itheima php
场景:在一个文件中,找到含有itcast的语句

测试文件


  
  
  1. hello itcast python
  2. www .itcast .cn c++
  3. itheima ios
  4. itheima php
场景:在一个文件中,找到邮箱为163或者126的所有邮件地址

re模块操作

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

1. re模块的使用过程


  
  
  1. #coding=utf-8
  2. # 导入re模块
  3. import re
  4. # 使用match方法进行匹配操作
  5. result = re.match(正则表达式,要匹配的字符串)
  6. # 如果上一步匹配到数据的话,可以使用group方法来提取数据
  7. result.group()

2. re模块示例(匹配以itcast开头的语句)


  
  
  1. #coding=utf-8
  2. import re
  3. result = re.match( "itcast", "itcast.cn")
  4. result.group()

运行结果为:

itcast

  
  

3. 说明

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

匹配单个字符

在上一小节中,了解到通过re模块能够完成使用正则表达式来匹配字符串

本小节,将要讲解正则表达式的单字符匹配

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

示例1: .


  
  
  1. #coding=utf-8
  2. import re
  3. ret = re.match( ".", "M")
  4. print(ret.group())
  5. ret = re.match( "t.o", "too")
  6. print(ret.group())
  7. ret = re.match( "t.o", "two")
  8. print(ret.group())

运行结果:


  
  
  1. M
  2. too
  3. two

示例2:[ ]


  
  
  1. #coding=utf-8
  2. import re
  3. # 如果hello的首字符小写,那么正则表达式需要小写的h
  4. ret = re.match( "h", "hello Python")
  5. print(ret.group())
  6. # 如果hello的首字符大写,那么正则表达式需要大写的H
  7. ret = re.match( "H", "Hello Python")
  8. print(ret.group())
  9. # 大小写h都可以的情况
  10. ret = re.match( "[hH]", "hello Python")
  11. print(ret.group())
  12. ret = re.match( "[hH]", "Hello Python")
  13. print(ret.group())
  14. ret = re.match( "[hH]ello Python", "Hello Python")
  15. print(ret.group())
  16. # 匹配0到9第一种写法
  17. ret = re.match( "[0123456789]Hello Python", "7Hello Python")
  18. print(ret.group())
  19. # 匹配0到9第二种写法
  20. ret = re.match( "[0-9]Hello Python", "7Hello Python")
  21. print(ret.group())
  22. ret = re.match( "[0-35-9]Hello Python", "7Hello Python")
  23. print(ret.group())
  24. # 下面这个正则不能够匹配到数字4,因此ret为None
  25. ret = re.match( "[0-35-9]Hello Python", "4Hello Python")
  26. # print(ret.group())

运行结果:


  
  
  1. h
  2. H
  3. h
  4. H
  5. Hello Python
  6. 7Hello Python
  7. 7Hello Python
  8. 7Hello Python

示例3:\d


  
  
  1. #coding=utf-8
  2. import re
  3. # 普通的匹配方式
  4. ret = re.match( "嫦娥1号", "嫦娥1号发射成功")
  5. print(ret.group())
  6. ret = re.match( "嫦娥2号", "嫦娥2号发射成功")
  7. print(ret.group())
  8. ret = re.match( "嫦娥3号", "嫦娥3号发射成功")
  9. print(ret.group())
  10. # 使用\d进行匹配
  11. ret = re.match( "嫦娥\d号", "嫦娥1号发射成功")
  12. print(ret.group())
  13. ret = re.match( "嫦娥\d号", "嫦娥2号发射成功")
  14. print(ret.group())
  15. ret = re.match( "嫦娥\d号", "嫦娥3号发射成功")
  16. print(ret.group())

运行结果:


  
  
  1. 嫦娥 1
  2. 嫦娥 2
  3. 嫦娥 3
  4. 嫦娥 1
  5. 嫦娥 2
  6. 嫦娥 3

说明

  • 其他的匹配符参见后面章节的讲解

    匹配多个字符

    匹配多个字符的相关格式

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

    示例1:*

    需求:匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( "[A-Z][a-z]*", "M")
    4. print(ret.group())
    5. ret = re.match( "[A-Z][a-z]*", "MnnM")
    6. print(ret.group())
    7. ret = re.match( "[A-Z][a-z]*", "Aabcdef")
    8. print(ret.group())

    运行结果:

    
        
        
    1. M
    2. Mnn
    3. Aabcdef

    示例2:+

    需求:匹配出,变量名是否有效

    
        
        
    1. #coding=utf-8
    2. import re
    3. names = [ "name1", "_name", "2_name", "__name__"]
    4. for name in names:
    5. ret = re.match( "[a-zA-Z_]+[\w]*",name)
    6. if ret:
    7. print( "变量名 %s 符合要求" % ret.group())
    8. else:
    9. print( "变量名 %s 非法" % name)

    运行结果:

    
        
        
    1. 变量名 name1 符合要求
    2. 变量名 _name 符合要求
    3. 变量名 2_name 非法
    4. 变量名 __name__ 符合要求

    示例3:?

    需求:匹配出,0到99之间的数字

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( "[1-9]?[0-9]", "7")
    4. print(ret.group())
    5. ret = re.match( "[1-9]?\d", "33")
    6. print(ret.group())
    7. ret = re.match( "[1-9]?\d", "09")
    8. print(ret.group())

    运行结果:

    
        
        
    1. 7
    2. 33
    3. 0 # 这个结果并不是想要的,利用$才能解决

    示例4:{m}

    需求:匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( "[a-zA-Z0-9_]{6}", "12a3g45678")
    4. print(ret.group())
    5. ret = re.match( "[a-zA-Z0-9_]{8,20}", "1ad12f23s34455ff66")
    6. print(ret.group())

    运行结果:

    
        
        
    1. 12a3g4
    2. 1ad12f23s34455ff66

    练一练

    题目1:匹配出163的邮箱地址,且@符号之前有4到20位,例如hello@163.com

    匹配开头结尾

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

    示例1:$

    需求:匹配163.com的邮箱地址

    
        
        
    1. #coding=utf-8
    2. import re
    3. email_list = [ "xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
    4. for email in email_list:
    5. ret = re.match( "[\w]{4,20}@163\.com", email)
    6. if ret:
    7. print( "%s 是符合规定的邮件地址,匹配后的结果是:%s" % (email, ret.group()))
    8. else:
    9. print( "%s 不符合要求" % email)

    运行结果:

    
        
        
    1. xiaoWang@ 163.com 是符合规定的邮件地址,匹配后的结果是:xiaoWang@ 163.com
    2. xiaoWang@ 163.comheihei 是符合规定的邮件地址,匹配后的结果是:xiaoWang@ 163.com
    3. .com.xiaowang@qq.com 不符合要求
    完善后
    
        
        
    1. email_list = [ "xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
    2. for email in email_list:
    3. ret = re.match( "[\w]{4,20}@163\.com$", email)
    4. if ret:
    5. print( "%s 是符合规定的邮件地址,匹配后的结果是:%s" % (email, ret.group()))
    6. else:
    7. print( "%s 不符合要求" % email)

    运行结果:

    
        
        
    1. xiaoWang@ 163.com 是符合规定的邮件地址,匹配后的结果是:xiaoWang@ 163.com
    2. xiaoWang@ 163.comheihei 不符合要求
    3. .com.xiaowang@qq.com 不符合要求

    匹配分组

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

    示例1:|

    需求:匹配出0-100之间的数字

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( "[1-9]?\d", "8")
    4. print(ret.group()) # 8
    5. ret = re.match( "[1-9]?\d", "78")
    6. print(ret.group()) # 78
    7. # 不正确的情况
    8. ret = re.match( "[1-9]?\d", "08")
    9. print(ret.group()) # 0
    10. # 修正之后的
    11. ret = re.match( "[1-9]?\d$", "08")
    12. if ret:
    13. print(ret.group())
    14. else:
    15. print( "不在0-100之间")
    16. # 添加|
    17. ret = re.match( "[1-9]?\d$|100", "8")
    18. print(ret.group()) # 8
    19. ret = re.match( "[1-9]?\d$|100", "78")
    20. print(ret.group()) # 78
    21. ret = re.match( "[1-9]?\d$|100", "08")
    22. # print(ret.group()) # 不是0-100之间
    23. ret = re.match( "[1-9]?\d$|100", "100")
    24. print(ret.group()) # 100

    示例2:( )

    需求:匹配出163、126、qq邮箱

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( "\w{4,20}@163\.com", "test@163.com")
    4. print(ret.group()) # test@163.com
    5. ret = re.match( "\w{4,20}@(163|126|qq)\.com", "test@126.com")
    6. print(ret.group()) # test@126.com
    7. ret = re.match( "\w{4,20}@(163|126|qq)\.com", "test@qq.com")
    8. print(ret.group()) # test@qq.com
    9. ret = re.match( "\w{4,20}@(163|126|qq)\.com", "test@gmail.com")
    10. if ret:
    11. print(ret.group())
    12. else:
    13. print( "不是163、126、qq邮箱") # 不是163、126、qq邮箱

    不是以4、7结尾的手机号码(11位)

    
        
        
    1. import re
    2. tels = [ "13100001234", "18912344321", "10086", "18800007777"]
    3. for tel in tels:
    4. ret = re.match( "1\d{9}[0-35-68-9]", tel)
    5. if ret:
    6. print(ret.group())
    7. else:
    8. print( "%s 不是想要的手机号" % tel)

    提取区号和电话号码

    
        
        
    1. >>> ret = re.match( "([^-]*)-(\d+)", "010-12345678")
    2. >>> ret.group()
    3. '010-12345678'
    4. >>> ret.group( 1)
    5. '010'
    6. >>> ret.group( 2)
    7. '12345678'

    示例3:\

    需求:匹配出<html>hh</html>

    
        
        
    1. #coding=utf-8
    2. import re
    3. # 能够完成对正确的字符串的匹配
    4. ret = re.match( "<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</html>")
    5. print(ret.group())
    6. # 如果遇到非正常的html格式字符串,匹配出错
    7. ret = re.match( "<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</htmlbalabala>")
    8. print(ret.group())
    9. # 正确的理解思路:如果在第一对<>中是什么,按理说在后面的那对<>中就应该是什么
    10. # 通过引用分组中匹配到的数据即可,但是要注意是元字符串,即类似 r""这种格式
    11. ret = re.match( r"<([a-zA-Z]*)>\w*</\1>", "<html>hh</html>")
    12. print(ret.group())
    13. # 因为2对<>中的数据不一致,所以没有匹配出来
    14. test_label = "<html>hh</htmlbalabala>"
    15. ret = re.match( r"<([a-zA-Z]*)>\w*</\1>", test_label)
    16. if ret:
    17. print(ret.group())
    18. else:
    19. print( "%s 这是一对不正确的标签" % test_label)

    运行结果:

    
        
        
    1. <html>hh </html>
    2. <html>hh </htmlbalabala>
    3. <html>hh </html>
    4. <html>hh </htmlbalabala> 这是一对不正确的标签

    示例4:\number

    需求:匹配出<html><h1>www.itcast.cn</h1></html>

    
        
        
    1. #coding=utf-8
    2. import re
    3. labels = [ "<html><h1>www.itcast.cn</h1></html>", "<html><h1>www.itcast.cn</h2></html>"]
    4. for label in labels:
    5. ret = re.match( r"<(\w*)><(\w*)>.*</\2></\1>", label)
    6. if ret:
    7. print( "%s 是符合要求的标签" % ret.group())
    8. else:
    9. print( "%s 不符合要求" % label)

    运行结果:

    
        
        
    1. <html> <h1>www.itcast.cn </h1> </html> 是符合要求的标签
    2. <html> <h1>www.itcast.cn </h2> </html> 不符合要求

    示例5:(?P<name>) (?P=name)

    需求:匹配出<html><h1>www.itcast.cn</h1></html>

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.match( r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.itcast.cn</h1></html>")
    4. ret.group()
    5. ret = re.match( r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.itcast.cn</h2></html>")
    6. ret.group()

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

    运行结果:

    re模块的高级用法

    search

    需求:匹配出文章阅读的次数

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.search( r"\d+", "阅读次数为 9999")
    4. ret.group()

    运行结果:

    '9999'
    
        
        

    findall

    需求:统计出python、c、c++相应文章阅读的次数

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.findall( r"\d+", "python = 9999, c = 7890, c++ = 12345")
    4. print(ret)

    运行结果:

    ['9999', '7890', '12345']
    
        
        

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

    需求:将匹配到的阅读次数加1

    方法1:

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.sub( r"\d+", '998', "python = 997")
    4. print(ret)

    运行结果:

    python = 998
    
        
        

    方法2:

    
        
        
    1. #coding=utf-8
    2. import re
    3. def add(temp):
    4. strNum = temp.group()
    5. num = int(strNum) + 1
    6. return str(num)
    7. ret = re.sub( r"\d+", add, "python = 997")
    8. print(ret)
    9. ret = re.sub( r"\d+", add, "python = 99")
    10. print(ret)

    运行结果:

    
        
        
    1. python = 998
    2. python = 100

    练习

    从下面的字符串中取出文本

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

    参考答案:

    re.sub(r"<[^>]*>|&nbsp;|\n", "", test_str)
    
        
        

    split 根据匹配进行切割字符串,并返回一个列表

    需求:切割字符串“info:xiaoZhang 33 shandong”

    
        
        
    1. #coding=utf-8
    2. import re
    3. ret = re.split( r":| ", "info:xiaoZhang 33 shandong")
    4. print(ret)

    运行结果:

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

    python贪婪和非贪婪

    Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;

    非贪婪则相反,总是尝试匹配尽可能少的字符。

    在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。

    
        
        
    1. >>> s= "This is a number 234-235-22-423"
    2. >>> r=re.match( ".+(\d+-\d+-\d+-\d+)",s)
    3. >>> r.group( 1)
    4. '4-235-22-423'
    5. >>> r=re.match( ".+?(\d+-\d+-\d+-\d+)",s)
    6. >>> r.group( 1)
    7. '234-235-22-423'
    8. >>>

    正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在我们上面的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。

    解决方式:非贪婪操作符“?”,这个操作符可以用在"*","+","?"的后面,要求正则匹配的越少越好。

    
        
        
    1. >>> re.match( r"aa(\d+)", "aa2343ddd").group( 1)
    2. '2343'
    3. >>> re.match( r"aa(\d+?)", "aa2343ddd").group( 1)
    4. '2'
    5. >>> re.match( r"aa(\d+)ddd", "aa2343ddd").group( 1)
    6. '2343'
    7. >>> re.match( r"aa(\d+?)ddd", "aa2343ddd").group( 1)
    8. '2343'
    9. >>>

    练一练

    字符串为:

    <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地址

    参考答案

    re.search(r"https://.*?\.jpg", test_str)
        
        

    r的作用

    
        
        
    1. >>> mm = "c:\\a\\b\\c"
    2. >>> mm
    3. 'c:\\a\\b\\c'
    4. >>> print(mm)
    5. c:\a\b\c
    6. >>> re.match( "c:\\\\",mm).group()
    7. 'c:\\'
    8. >>> ret = re.match( "c:\\\\",mm).group()
    9. >>> print(ret)
    10. c:\
    11. >>> ret = re.match( "c:\\\\a",mm).group()
    12. >>> print(ret)
    13. c:\a
    14. >>> ret = re.match( r"c:\\a",mm).group()
    15. >>> print(ret)
    16. c:\a
    17. >>> ret = re.match( r"c:\a",mm).group()
    18. Traceback (most recent call last):
    19. File "<stdin>", line 1, in <module>
    20. AttributeError: 'NoneType' object has no attribute 'group'
    21. >>>

    说明

    Python中字符串前面加上 r 表示原生字符串

    与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。

    Python里的原生字符串很好地解决了这个问题,有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

    
        
        
    1. >>> ret = re.match( r"c:\\a",mm).group()
    2. >>> print(ret)
    3. c:\a
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值