正则

一、正则基础

1 []  原子表
[a]   匹配小写字母a
[x]   匹配小写字母x
[ab]  匹配小写字母a或b
[abc] 匹配小写字母a或者b或者c
[0123456789]  匹配任意一位数字
[0-9] 匹配任意一位数字
[a-z] 匹配任意一位小写字母
[A-Z] 匹配任意一位大写字母
[a-zA-Z]  匹配任意一位字母
[0-9a-zA-Z]  匹配任意一位字母或一位数字
以上都是一位

2 ^ 以...开头
^a     匹配一个小写字母a 并且必须作为开头  ba   ab
^abc   匹配小写字母abc  并且abc作为开头   abcd    bbabcd
^[a]   等同于^a
^[abc] 匹配一位小写字母a或b或c 并且作为开头
[^abc] 匹配一位非小写字母a或b或c


3 $  以...作为结尾 一般用不到  ^ 和 $通常是组合匹配
^123456$   完全匹配  通常这样的写法使用  完全匹配  咱们上面讲的都是包含关系
^1[3-9][0-9]{9}$  匹配第一位为1 第二位为3-9 剩下的9位为0-9   完全匹配
                    199012345678
                    1990123456789

4 {m}  限定符  前面正则的m次  不能单独使用
[a-z]{9}  匹配9位小写字母
[0-9][a-z]{9}  匹配一位数字和9位小写字母

5 {m, n}    限定符  前面正则的m-n次  不能单独使用
[a-zA-Z]{3, 5}  匹配3-5位的字母

6 {m, }      限定符  前面正则的至少m次  不能单独使用
[a-zA-Z]{3,}  匹配至少3位的字母

7 ?     匹配0-1次
-?[1-9]   匹配正负1-9
-{0, 1}[1-9]  等同于上方

-[1-9]{0,1}
匹配一个符号-或-1-9 的数字

8 .    匹配换行符以外的任意一位字符

9 *    匹配任意次 {0, }

10 .*?  匹配换行符以外的任意字符任意次  最重要的!!!!!!! 非贪婪

11 .*  匹配换行符以外的任意字符任意次  不重要!!!!!!! 贪婪

11 +   匹配至少次 {1, }

12 .+?  匹配换行符以外的任意字符至少1次 非贪婪

13 .+  匹配换行符以外的任意字符至少1次 贪婪

14 ()   一个单元和子存储
(ab)|(bc)

15 |  或
a|b

16 \w  匹配数字字母下划线 一位

17 \W  和上面取反  匹配非数字字母下划线 一位

18 \d  匹配0-9  也就是[0-9]简写 一位

19 \D  上面的取反

20 \s  匹配空白字符

21 \S  上面的取反

1、为什么使用正则

  • 需求

    判断一个字符串是否是手机号

  • 解决

    编写一个函数,给函数一个字符串,如果是手机号则返回True,否则返回False

  • 代码

    def isPhone(phone):
        # 长度为11
        # 全部都是数字字符
        # 以1开头
        pass
    
    if isPhone("13812345678"):
        print("是手机号")
    else:
        print("不是手机号")
    
  • 注意

    如果使用正则会让这个问题变得简单

2、正则与re模块简介

概述: 正则表达式,又称规则表达式

正则表达式(regular expression)描述了一种字符串匹配的模式(pattern)

正则匹配是一个 模糊的匹配(不是精确匹配)

re:python自1.5版本开始增加了re模块,该模块提供了perl风格的正则表达式模式,re模块是python语言拥有了所有正则表达式的功能

  • 如下四个方法经常使用
    • match()
    • search()
    • findall()
    • finditer()

二、正则表达式

1、匹配单个字符与数字

匹配 说明
. 匹配除换行符以外的任意字符,当flags被设置为re.S时,可以匹配包含换行符以内的所有字符
[] 里面是字符集合,匹配[]里任意一个字符
[0123456789] 匹配任意一个数字字符
[0-9] 匹配任意一个数字字符
[a-z] 匹配任意一个小写英文字母字符
[A-Z] 匹配任意一个大写英文字母字符
[A-Za-z] 匹配任意一个英文字母字符
[A-Za-z0-9] 匹配任意一个数字或英文字母字符
[^lucky] []里的^称为脱字符,表示非,匹配不在[]内的任意一个字符
[1] 以[]中内的某一个字符作为开头
\d 匹配任意一个数字字符,相当于[0-9]
\D 匹配任意一个非数字字符,相当于[^0-9]
\w 匹配字母、下划线、数字中的任意一个字符,相当于[0-9A-Za-z_]
\W 匹配非字母、下划线、数字中的任意一个字符,相当于[^0-9A-Za-z_]
\s 匹配空白符(空格、换页、换行、回车、制表),相当于[ \f\n\r\t]
\S 匹配非空白符(空格、换页、换行、回车、制表),相当于[^ \f\n\r\t]

2、匹配锚字符

锚字符:用来判定是否按照规定开始或者结尾

匹配 说明
^ 行首匹配,和[]里的^不是一个意思
$ 行尾匹配

3、限定符

限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 * 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。

匹配 说明
(xyz) 匹配括号内的xyz,作为一个整体去匹配 一个单元 子存储
x? 匹配0个或者1个x,非贪婪匹配
x* 匹配0个或任意多个x
x+ 匹配至少一个x
x 确定匹配n个x,n是非负数
x 至少匹配n个x
x 匹配至少n个最多m个x
x|y |表示或的意思,匹配x或y

4、通用flags(修正符)

说明
re.I 是匹配对大小写不敏感
re.S 使.匹配包括换行符在内的所有字符 re.findall(ex, page_text, re.S) 单行匹配
re.M 多行匹配

三、re模块中常用函数

通用函数

  • 获取匹配结果

    • 使用group()方法 获取到匹配的值

    • groups() 返回一个包含所有小组字符串的元组(也就是自存储的值),从 1 到 所含的小组号。

1、match()函数

import re


# 只匹配一次  和search的区别为 match必须从第一位开始进行匹配 相当于正则前有^
# 获取里面的值使用group
print(re.match('a', 'abcde'))   # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.match('a', 'bacde'))   # None

print(re.match('1[3-9]\d{9}$', '18826123678'))  # <_sre.SRE_Match object; span=(0, 11), match='18826123678'>
print(re.match('1[3-9]\d{9}$', '18826123678123'))   # None

  • 原型

    def match(pattern, string, flags=0)
    
  • 功能

    匹配成功返回 匹配的对象

    匹配失败 返回 None

  • 获取匹配结果

    • 使用group()方法 获取到匹配的值

    • groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

  • 注意:从第一位开始匹配 只匹配一次

  • 参数

    参数 说明
    pattern 匹配的正则表达式(一种字符串的模式)
    string 要匹配的字符串
    flags 标识位,用于控制正则表达式的匹配方式
  • 代码

    import re
    
    res = re.match('\d{2}','123')
    print(res.group())
    
    #给当前匹配到的结果起别名
    s = '3G4HFD567'
    re.match("(?P<value>\d+)",s)
    print(x.group(0))
    print(x.group('value'))
    

2、search()函数

import re

# 只匹配一次 成功返回对象  失败为None
print(re.search('[a]', 'abcdefg').group())  # a
print(re.search('[x]', 'abcdefg'))  # 匹配失败为None
print(re.search('[ab]', 'abcdefg'))  # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search('[A-Z]', 'abcdefg'))    # None
print(re.search('[a-z]', 'abcdefg'))    # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search('[A-Za-z]', 'abcdefg'))  # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search('\d', 'abcdefg'))   # None
print(re.search('[a-z]', '123abcdefg')) # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search('\d', '123abcdefg'))    # <_sre.SRE_Match object; span=(0, 1), match='1'>
print(re.search('\D', '123abcdefg'))    # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(re.search('\w', '123abcdefg'))    # <_sre.SRE_Match object; span=(0, 1), match='1'>
print(re.search('\W', '123abcdefg'))    # None
print(re.search('\d{2}', '123abcdefg')) # <_sre.SRE_Match object; span=(0, 2), match='12'>
print(re.search('\d{5}', '123abcdefg')) # None
print(re.search('\d{2,5}', '123abcdefg'))   # <_sre.SRE_Match object; span=(0, 3), match='123'>
print(re.search('\d{2,}', '123abcdefg'))    # <_sre.SRE_Match object; span=(0, 3), match='123'>
print(re.search('a', '123abcdefg')) # <_sre.SRE_Match object; span=(0, 3), match='a'>
print(re.search('^a', '123abcdefg'))    # None
print(re.search('^\d', '123abcdefg'))   # <_sre.SRE_Match object; span=(0, 3), match='1'>
print(re.search('1[3-9]\d{9}', '18826123678'))  # <_sre.SRE_Match object; span=(0, 11), match='18826123678'>
print(re.search('1[3-9]\d{9}', '18826123678123'))   # <_sre.SRE_Match object; span=(0, 11), match='18826123678'>
print(re.search('^1[3-9]\d{9}$', '18826123678123')) # None
print(re.search('^1[3-9]\d{9}$', '18826123678'))  # <_sre.SRE_Match object; span=(0, 11), match='18826123678'>

  • 原型

    def search(pattern, string, flags=0)
    
  • 功能

    扫描整个字符串string,并返回第一个pattern模式成功的匹配

    匹配失败 返回 None

  • 参数

    参数 说明
    pattern 匹配的正则表达式(一种字符串的模式)
    string 要匹配的字符串
    flags 标识位,用于控制正则表达式的匹配方式
  • 注意:

    只要字符串包含就可以

    只匹配一次

  • 示例

    import re
    
    res = re.search('[a-z]', '131A3ab889s')
    print(res)
    print(res.group()
    
  • 注意

    与search的区别

    相同点:

    都只匹配一次

    不同点:

    • search是在要匹配的字符串中 包含正则表达式的内容就可以
    • match 必须第一位就开始匹配 否则匹配失败

3、findall()函数(返回列表)

import re

# 返回列表  匹配所有
print(re.findall('[a-z]', 'abcdefg'))   # ['a', 'b', 'c', 'd', 'e', 'f', 'g']

# 贪婪
Str = "<b>加粗标签1</b><b>加粗标签2</b><b>加粗标签3</b>"
# Str = "<b>加粗标签1</b><b>加粗标签2</b><b></b>"
# 匹配所有的b标签
print(re.findall('<b>.*</b>', Str))  # ['<b>加粗标签1</b><b>加粗标签2</b><b>加粗标签3</b>']
print(re.findall('<b>.+</b>', Str))  # ['<b>加粗标签1</b><b>加粗标签2</b><b>加粗标签3</b>']


# 非贪婪
print(re.findall('<b>.*?</b>', Str))    # ['<b>加粗标签1</b>', '<b>加粗标签2</b>', '<b>加粗标签3</b>']
print(re.findall('<b>.+?</b>', Str))    # ['<b>加粗标签1</b>', '<b>加粗标签2</b>', '<b>加粗标签3</b>']

Str = "<b>加粗标签1</b></b>"
print(re.findall('<b>.*?</b>', Str))    # ['<b>加粗标签1</b>']
print(re.findall('<b>.*</b>', Str))     # ['<b>加粗标签1</b></b>']
  • 原型

    def findall(pattern, string, flags=0)
    
  • 功能

    扫描整个字符串string,并返回所有匹配的pattern模式结果的字符串列表

  • 参数

    参数 说明
    pattern 匹配的正则表达式(一种字符串的模式)
    string 要匹配的字符串
    flags 标识位,用于控制正则表达式的匹配方式
  • 示例

    myStr = """
    <a href="http://www.baidu.com">百度</a>
    <A href="http://www.taobao.com">淘宝</A>
    <a href="http://www.id97.com">电
    影网站</a>
    <i>我是倾斜1</i>
    <i>我是倾斜2</i>
    <em>我是倾斜2</em>
    """
    # html里是不区分大小写
    # (1)给正则里面匹配的 加上圆括号 会将括号里面的内容进行 单独的返回
    res = re.findall("(<a href=\"http://www\.(.*?)\.com\">(.*?)</a>)",myStr) #[('<a href="http://www.baidu.com">百度</a>', 'baidu', '百度')]
    
    # 括号的区别
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr) #['<a href="http://www.baidu.com">百度</a>']
    
    #(2) 不区分大小写的匹配
    res = re.findall("<a href=\"http://www\..*?\.com\">.*?</a>",myStr,re.I) #['<a href="http://www.baidu.com">百度</a>', '<A href="http://www.taobao.com">淘宝</A>']
    res = re.findall("<[aA] href=\"http://www\..*?\.com\">.*?</[aA]>",myStr) #['<a href="http://www.baidu.com">百度</a>']
    # (3) 使.支持换行匹配
    res = re.findall("<a href="http://www..?.com">.?</a>",myStr,re.S) #
    # (4) 支持换行 支持不区分大小写匹配
    res = re.findall("<a href="http://www..?.com">.?</a>",myStr,re.S|re.I) #
    print(res)
    

4、finditer()函数

import re

# 返回迭代器  匹配所有 和findall一样 只是返回类型不同
# print(re.findall('[a-z]', 'abcdefg'))
res = re.finditer('[a-z]', 'abcdefg')
print(res)  # <callable_iterator object at 0x000002041D548F98>
print(next(res).group())    # a

for o in res:
    print(o.group())
  • 原型

    def finditer(pattern, string, flags=0)
    
  • 功能

    与findall()类似,返回一个迭代器

  • 参数

    参数 说明
    pattern 匹配的正则表达式(一种字符串的模式)
    string 要匹配的字符串
    flags 标识位,用于控制正则表达式的匹配方式
  • 代码

    import re
    
    res = re.finditer('\w', '12hsakda1')
    print(res)
    print(next(res))
    
    for i in res:
        print(i)
    

5、split()函数

import re

# split 拆分
print(re.split('\d', 'abc1defg2qwe'))  # ['abc', 'defg', 'qwe']
print(re.split('\s', 'abc\rdefg\nqwe'))  # ['abc', 'defg', 'qwe']

# sub  正则替换
print(re.sub('\s', '', 'abc\rdefg\nq' 'we'))  # abcdefgqwe
print(repr(re.sub('[a-z]', '------',
                  'abc\rdefg\nq' 'we')))  # '------------------\r------------------------\n------------------'
  • 作用:切割字符串

  • 原型:

    def split(patter, string, maxsplit=0, flags=0)
    
  • 参数

    pattern 正则表达式

    string 要拆分的字符串

    maxsplit 最大拆分次数 默认拆分全部

    flags 修正符

  • 示例

    import re
    myStr = "asdas\rd&a\ts12d\n*a3sd@a_1sd"
    #通过特殊字符 对其进行拆分 成列表
    res = re.split("[^a-z]",myStr)
    res = re.split("\W",myStr)
    

6、修正符

  • 作用

    对正则进行修正

  • 使用

    search/match/findall/finditer 等函数 flags参数的使用

  • 修正符

    re.I 不区分大小写匹配

    re.S 使.可以匹配换行符 匹配任意字符

  • 使用

    re.I

    print(re.findall('[a-z]','AaBb'))
    print(re.findall('[a-z]','AaBb', flags=re.I))
    

    re.S

    print(re.findall('<b>.*?</b>','<b>b标签</b>'))
    print(re.findall('<b>.*?</b>','<b>b标\n签</b>', flags=re.S))
    

四、正则高级

1、分组&起名称

import re


Str = """
<a href="http://www.baidu.com">百度</a>
<a href="http://www.taobao.com">淘
宝</a>
<A href="http://www.sina.com">新浪</A>
<b>加粗标签</b>
"""
# 匹配除所有的超链接a
# print(re.findall('<a href=".*?">.*?</a>', Str))
# 修正符 re.I  不区分大小写  re.S  使.可以匹配换行符  也就是.*?无敌存在
# print(re.findall('<a href=".*?">.*?</a>', Str, re.I))
# print(re.findall('<a href=".*?">.*?</a>', Str, re.I|re.S))
# print(re.findall('<[aA] href=".*?">.*?</[Aa]>', Str, re.S))


# 只要超链接
# print(re.findall('<a href="(.*?)">.*?</a>', Str, re.S|re.I))
# print(re.findall('<a href="(.*?)">(.*?)</a>', Str, re.S|re.I))
# print(re.findall('(<a href="(.*?)">(.*?)</a>)', Str, re.S|re.I))


import re

# print(re.search('<b>.*?</b>', '<b>加粗1</b>').group())    # <b>加粗1</b>
# print(re.search('<b>.*?</b>', '<b>加粗1</b>').groups())   # ()

# print(re.search('<b>(.*?)</b>', '<b>加粗1</b>').group())  # <b>加粗1</b>
# print(re.search('<b>(.*?)</b>', '<b>加粗1</b>').group(0)) # <b>加粗1</b>
# print(re.search('<b>(.*?)</b>', '<b>加粗1</b>').group(1)) # 加粗1
# 起名称
print(re.search('<b>(?P<val>.*?)</b>', '<b>加粗1</b>').group('val'))  # 加粗1
# 括号中的内容进行返回
print(re.search('<b>(.*?)</b>', '<b>加粗1</b>').groups())  # ('加粗1',)
  • 概念

    处理简单的判断是否匹配之外,正则表达式还有提取子串的功能,用()表示的就是要提取的分组

  • 代码

    #给当前匹配到的结果起别名
    s = '3G4HFD567'
    re.match("(?P<value>\d+)",s)
    print(x.group(0))
    print(x.group('value'))
    
  • 说明

    • 正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来
    • group(0)永远是原始字符串,group(1)、group(2)……表示第1、2、……个子串

2、编译

import re

# compile 编译正则表达式对象 一般不用
# split 拆分
pattern = re.compile('\d')
print(pattern.split('abc1defg2qwe'))    # ['abc', 'defg', 'qwe']
  • 概念

    当在python中使用正则表达式时,re模块会做两件事,一件是编译正则表达式,如果表达式的字符串本身不合法,会报错。另一件是用编译好的正则表达式提取匹配字符串

  • 编译优点

    如果一个正则表达式要使用几千遍,每一次都会编译,出于效率的考虑进行正则表达式的编译,就不需要每次都编译了,节省了编译的时间,从而提升效率

  • compile()函数

    • 原型

      def compile(pattern, flags=0)
      
    • 作用

      将pattern模式编译成正则对象

    • 参数

      参数 说明
      pattern 匹配的正则表达式(一种字符串的模式)
      flags 标识位,用于控制正则表达式的匹配方式
    • flags

      说明
      re.I 是匹配对大小写不敏感
      re.S 使.匹配包括换行符在内的所有字符
    • 返回值

      编译好的正则对象

    • 示例

      import re
      
      re_phone = re.compile(r"(0\d{2,3}-\d{7,8})")
      print(re_phone, type(re_phone))
      
  • 编译后其他方法的使用

    原型

    def match(self, string, pos=0, endpos=-1)
    def search(self, string, pos=0, endpos=-1)
    def findall(self, string, pos=0, endpos=-1)
    def finditer(self, string, pos=0, endpos=-1)
    

    参数

    参数 说明
    string 待匹配的字符串
    pos 从string字符串pos下标开始
    endpos 结束下标

    示例

    s1 = "lucky's phone is 010-88888888"
    s2 = "kaige's phone is 010-99999999"
    ret1 = re_phone.search(s1)
    print(ret1, ret1.group(1))
    ret2 = re_phone.search(s2)
    print(ret2, ret2.group(1))
    

3、贪婪与非贪婪

  • 贪婪模式

    贪婪概念:匹配尽可能多的字符

    • .+ 匹配换行符以外的字符至少一次
    • .* 匹配换行符以外的字符任意次

    实例

    res = re.search('<b>.+</b>', '<b></b><b>b标签</b>')
    res = re.search('<b>.*</b>', '<b>b标签</b><b>b标签</b><b>b标签</b><b>b标签</b>')
    
  • 非贪婪模式

    非贪婪概念:尽可能少的匹配称为非贪婪匹配,*?、+?即可

  • .+? 匹配换行符以外的字符至少一次 拒绝贪婪

    • .*? 匹配换行符以外的字符任意次 拒绝贪婪

    实例

    res = re.search('<b>.+?</b>', '<b>b标签</b><b>b标签</b>')
    res = re.search('<b>.*?</b>', '<b>b标签</b><b>b标签</b><b>b标签</b><b>b标签</b>'
    

  1. lucky ↩︎

posted @ 2023-03-18 10:05  凫弥  阅读(37)  评论(0编辑  收藏  举报