081 re正则表达式模块

Posted xuchengnotes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了081 re正则表达式模块相关的知识,希望对你有一定的参考价值。

一、正则表达式

正则表达式本身是一种小型的、高度专业化的编程语言,它并不是Python的一部分。
如果已经在其他语言里使用过正则表达式,只需要简单看一看就可以上手了。
而在python中,通过内嵌集成re模块程序员们可以直接调用来实现正则匹配

正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,看下图中的示例以及自己多使用几次就能明白。

下图列出了Python支持的正则表达式元字符和语法

技术图片

二、re模块的基本语法

^ 元字符

字符串开始位置与匹配规则符合就匹配,否则不匹配

匹配字符串开头。在多行模式中匹配每一行的开头(Python3+已经失效,配合compile使用)

import re
s = '王大炮打炮被大炮打死了 王大炮打炮被大炮打死了'
# ^: 匹配开头
print(re.findall("^王大炮", s))

[‘王大炮‘]

$ 元字符

字符串结束位置与匹配规则符合就匹配,否则不匹配

匹配字符串末尾,在多行模式中匹配每一行的末尾

import re
s = '王大炮打炮被大炮打死了 王大炮打炮被大炮打死了'
# $: 匹配结尾
print(re.findall("打死了$", s))

[‘打死了‘]

[] 元字符(字符集)

匹配中间的字符,只要单个字符

也可以使用[a-z]表示a到z 单个字符

import re
s = "adasdasdasdasfasf\n\t"
# []: 匹配中间的字符,只要单个字符
print(re.findall("[acef]",s))

[‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘f‘, ‘a‘, ‘f‘]

[^] 反取

^对[]内的元素取反,除了[]里的字符都要

import re
s = "adasdasdasdasfasf\n\t"
# [^] : 把[]中的字符给排除.
print(re.findall("[^acef]",s))

[‘d‘, ‘s‘, ‘d‘, ‘s‘, ‘d‘, ‘s‘, ‘d‘, ‘s‘, ‘s‘, ‘\n‘, ‘\t‘]

. 任意字符(换行符除外)

表示任意单个字符

import re
s= 'abc12ab56bc'
# .: 任意字符(换行符除外)
print(re.findall(".",s))

[‘a‘, ‘d‘, ‘a‘, ‘s‘, ‘d‘, ‘a‘, ‘s‘, ‘d‘, ‘a‘, ‘s‘, ‘d‘, ‘a‘, ‘s‘, ‘f‘, ‘a‘, ‘s‘, ‘f‘, ‘\t‘]

* 对前一个字符0-无穷次扩展

: 匹配 前面的字符0-无穷个,空也会匹配

import re
s = r"abaacaaaaa"
# *: 匹配 *前面的字符0-无穷个
print(re.findall("a*",s))     # 匹配 0-无限个a,空也会匹配

[‘a‘, ‘‘, ‘aa‘, ‘‘, ‘aaaaa‘, ‘‘]

+ 对前一个字符1-无穷次扩展

+: 匹配 +前面的字符1-无穷个

import re
s = r"abaacaaaaa"
# +: 匹配 +前面的字符1-无穷个
print(re.findall("a+",s))     # 匹配 1-无限个a

[‘a‘, ‘aa‘, ‘aaaaa‘]

? 对前一个字符0或1次扩展

?: 匹配 ?前面的字符0或1次扩展

import re
s = r"abaacaaaaa"
# ?: 匹配 ?前面的字符0-1个
print(re.findall("a?",s))     # 匹配 0-1个a

[‘a‘, ‘‘, ‘a‘, ‘a‘, ‘‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘‘]

m 对前一个字符扩展m次

m: 匹配 m前面的字符m次

import re
s = r"abaacaaaaa"
# m: 匹配 前面的字符m个
print(re.findall("a2",s))   # 匹配 2个a

[‘aa‘, ‘aa‘, ‘aa‘]

m,n 对前一个字符扩展m-n次(含n)

m,n: 匹配 前面的的字符m-n个

import re
s = r"abaacaaaaa"
# m,n: 匹配 前面的的字符m-n个
print(re.findall("a2,3",s))   # 匹配 2、3个a

[‘aa‘, ‘aaa‘, ‘aa‘]

\d 匹配单个数字(0-9)

\d: 匹配单个数字

import re
s = '1#@¥23abc123 \n_def\t456'
# \d: 匹配单个数字
print(re.findall("\d",s))   # 匹配 单个数字

[‘1‘, ‘2‘, ‘3‘, ‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘, ‘6‘]

\D 匹配单个非数字(包括\n)

\D: 匹配单个非数字

import re
s = '1#@¥23abc123 \n_def\t456'
# \D: 匹配单个非数字
print(re.findall("\D",s))   # 匹配 单个 非数字(包括\n)

[‘#‘, ‘@‘, ‘¥‘, ‘a‘, ‘b‘, ‘c‘, ‘ ‘, ‘\n‘, ‘_‘, ‘d‘, ‘e‘, ‘f‘, ‘\t‘]

\w 匹配 数字/字母/下划线

\w: 匹配 数字/字母/下划线

import re
s = '1#@¥23abc123 \n_def\t456'
# \w: 匹配 数字/字母/下划线
print(re.findall("\w",s))

[‘1‘, ‘2‘, ‘3‘, ‘a‘, ‘b‘, ‘c‘, ‘1‘, ‘2‘, ‘3‘, ‘_‘, ‘d‘, ‘e‘, ‘f‘, ‘4‘, ‘5‘, ‘6‘]

\W 匹配 非数字/非字母/非下划线

\W: 非数字/非字母/非下划线

import re
s = '1#@¥23abc123 \n_def\t456'
# \W: 非数字/非字母/非下划线
print(re.findall("\W",s))

[‘#‘, ‘@‘, ‘¥‘, ‘ ‘, ‘\n‘, ‘\t‘]

\s 匹配 空格/ \t/ \n

\s: 空格/ \t/ \n

import re
s = '1#@¥23abc123 \n_def\t456'
# \s: 空格/ \t/ \n
print(re.findall("\s", s))

[‘ ‘, ‘\n‘, ‘\t‘]

\S 匹配 非空格/ 非\t/ 非\m

\S: 非空格/ 非\t/ 非\m

import re
s = '1#@¥23abc123 \n_def\t456'
# \S: 非空格/ 非\t/ 非\m
print(re.findall("\S", s))

[‘1‘, ‘#‘, ‘@‘, ‘¥‘, ‘2‘, ‘3‘, ‘a‘, ‘b‘, ‘c‘, ‘1‘, ‘2‘, ‘3‘, ‘_‘, ‘d‘, ‘e‘, ‘f‘, ‘4‘, ‘5‘, ‘6‘]

() 只要括号内的

(): 只要括号内的

import re
s = 'abacad'
# (): 只要括号内的
print(re.findall('a(.)', s))

[‘b‘, ‘c‘, ‘d‘]

| 左右两边的字符都要

A|B: A和B都要

import re
s = 'abacad'
# A|B: A和B都要
print(re.findall('a|b', s))

[‘a‘, ‘b‘, ‘a‘, ‘a‘]

.* 贪婪模式

.*: 贪婪模式(最大化),找到继续找,让结果最大化

import re
s = 'abbbcabc'
# .*: 贪婪模式(最大化),找到继续找,让结果最大化
print(re.findall('a.*c', s))
print(re.findall('a.+c', s))

[‘abbbcabc‘]
[‘abbbcabc‘]

**.*? 非贪婪模式**

.*?: 非贪婪模式(最小化),找到就马上停止

import re
s = 'abbbcabc'
# .*?: 非贪婪模式(最小化),找到就马上停止
print(re.findall('a.*?c', s))
print(re.findall('a.+?c', s))

[‘abbbc‘, ‘abc‘]
[‘abbbc‘, ‘abc‘]

三、re模块中常用功能函数

3.1 正则表达式的两种书写方式

1.一种是直接在函数里书写规则,推荐使用

import re
a = re.findall("匹配规则", "这个字符串是否有匹配规则的字符")
print(a)

2.另一种是先将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。

import re

# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')

# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match = pattern.match('hello world!')

if match:
    # 使用Match获得分组信息
    print(match.group())
hello

3.2 re.compile(strPattern[, flag])函数

这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。 第二个参数flag是匹配模式,取值可以使用按位或运算符‘|‘表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile(‘pattern‘, re.I | re.M)与re.compile(‘(?im)pattern‘)是等价的。

下表是所有的正则匹配模式:

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

3.2.1 re.S

  • 在Python的正则表达式中,有一个参数为re.S。它表示 “.” 的作用扩展到整个字符串,包括“\n”。看如下代码:
import re
a = '''asdfhellopass:
    worldaf
    '''
b = re.findall('hello(.*?)world', a)
c = re.findall('hello(.*?)world', a, re.S)
print('b is ', b)
print('c is ', c)
b is  []
c is  ['pass:\n    ']

正则表达式中,“.”的作用是匹配除“\n”以外的任何字符,也就是说,它是在一行中进行匹配。这里的“行”是以“\n”进行区分的。a字符串有每行的末尾有一个“\n”,不过它不可见。

如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始,不会跨行。而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,将“\n”当做一个普通的字符加入到这个字符串中,在整体中进行匹配。

3.2.2 re.I

  • 不区分大小写
res = re.findall(r"A", "abc", re.I)
print(res)
['a']

3.2.3 re.M

  • 将所有行的尾字母输出(python3+已经无效)
s = '12 34/n56 78/n90'

re.findall(r'^/d+', s, re.M)  # 匹配位于行首的数字  # ['12', '56', '90']
re.findall(r'/A/d+', s, re.M)  # 匹配位于字符串开头的数字  # ['12']
re.findall(r'/d+$', s, re.M)  # 匹配位于行尾的数字  # ['34', '78', '90']
re.findall(r'/d+/Z', s, re.M)  # 匹配位于字符串尾的数字  # ['90']

3.2.4 re.sub

# 要求结果:['12', '23', '34']
l = ['1 2 ', '2   3', '  3 4']
import re
print(eval(re.sub(r'\s*', '', str(l))))
['12', '23', '34']

3.3 分组函数

?P<n1> # ?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容(只对正则函数返回对象时有用)

取出匹配对象方法

只对正则函数返回对象的有用

  • group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2
  • groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
  • groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果

3.4 re.match(pattern, string[, flags])函数(常用)

match,从头匹配一个符合规则的字符串,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
match(pattern, string, flags=0)

  • pattern: 正则模型
  • string : 要匹配的字符串
  • falgs : 匹配模式

注意:match()函数 与 search()函数基本是一样的功能,不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,search()是在字符串全局匹配第一个合规则的字符串

import re
# 无分组
origin = "hello egon bcd egon lge egon acd 19"
r = re.match("h\w+", origin)  # match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
hello
()

# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
r = re.match("h(\w+)", origin)  # match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
hello
('ello',)

# 有两个分组定义了key
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
# ?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容
r = re.match("(?P<n1>h)(?P<n2>\w+)", origin)
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
hello
('h', 'ello')
'n1': 'h', 'n2': 'ello'

3.5 re.search(pattern, string[, flags])函数

search,浏览全部字符串,匹配第一符合规则的字符串,浏览整个字符串去匹配第一个,未匹配成功返回None

search(pattern, string, flags=0)

  • pattern: 正则模型
  • string : 要匹配的字符串
  • falgs : 匹配模式

注意:match()函数 与 search()函数基本是一样的功能,不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,search()是在字符串全局匹配第一个合规则的字符串

import re
# 无分组
origin = "hello alex bcd alex lge alex acd 19"
# search浏览全部字符串,匹配第一符合规则的字符串,浏览整个字符串去匹配第一个,未匹配成功返回None
r = re.search("a\w+", origin)
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
alex
()

# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
r = re.search("a(\w+).*(\d)", origin)
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
alex bcd alex lge alex acd 19
('lex', '9')

# 有两个分组定义了key
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
# ?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容
r = re.search("a(?P<n1>\w+).*(?P<n2>\d)", origin)
print(r.group())  # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来
print(r.groups())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
print(r.groupdict())  # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
alex bcd alex lge alex acd 19
('lex', '9')
'n1': 'lex', 'n2': '9'

3.6 re.findall(pattern, string[, flags])函数(常用)

findall(pattern, string, flags=0)

  • pattern: 正则模型
  • string : 要匹配的字符串
  • falgs : 匹配模式

浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中,未匹配成功返回空列表

注意:一旦匹配成,再次匹配,是从前一次匹配成功的,后面一位开始的,也可以理解为匹配成功的字符串,不在参与下次匹配

import re
# 无分组
r = re.findall("\d+\w\d+", "a2b3c4d5")  # 浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)  # 注意:匹配成功的字符串,不在参与下次匹配,所以3c4也符合规则但是没匹配到
['2b3', '4d5']

注意:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表

import re
# 无分组
r = re.findall("", "a2b3c4d5")  # 浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)  # 注意:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表
['', '', '', '', '', '', '', '', '']

注意:正则匹配到空字符的情况,如果规则里只有一个组,而组后面是就表示组里的内容可以是0个或者多过,这样组里就有了两个意思,一个意思是匹配组里的内容,二个意思是匹配组里0内容(即是空白)所以尽量避免用否则会有可能匹配出空字符串

注意:正则只拿组里最后一位,如果规则里只有一个组,匹配到的字符串里在拿组内容是,拿的是匹配到的内容最后一位

import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("(a)*", origin)
print(r)
['', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '', '', '', '', '', 'a', '', '', '', '', 'a', '', '', '', '', '', '']

无分组:匹配所有合规则的字符串,匹配到的字符串放到一个列表中

import re
# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a\w+", origin)  # 浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中
print(r)
['alex', 'alex', 'alex', 'acd']

有分组:只将匹配到的字符串里,组的部分放到列表里返回,相当于groups()方法

import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.findall("a(\w+)", origin)  # 有分组:只将匹配到的字符串里,组的部分放到列表里返回
print(r)
['lex', 'lex', 'lex', 'cd']

多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返

相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回

import re
origin = "hello alex bcd alex lge alex acd 19"
# 多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返回
r = re.findall("(a)(\w+)", origin)
print(r)
[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')]

分组中有分组:只将匹配到的字符串里,组的部分放到一个元组中,先将包含有组的组,看作一个整体也就是一个组,把这个整体组放入一个元组里,然后在把组里的组放入一个元组,最后将所有组放入一个列表返回

import re
origin = "hello alex bcd alex lge alex acd 19"
# 分组中有分组:只将匹配到的字符串里,组的部分放到一个元组中,先将包含有组的组,看作一个整体也就是一个组,把这个整体组放入一个元组里,然后在把组里的组放入一个元组,最后将所有组放入一个列表返回
r = re.findall("(a)(\w+(e))", origin)
print(r)
[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')]

?:在有分组的情况下findall()函数,不只拿分组里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正则对象的函数如findall()

import re
origin = "hello alex bcd alex lge alex acd 19"
# ?:在有分组的情况下,不只拿分组里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正则对象的函数如findall()
b = re.findall("a(?:\w+)", origin)
print(b)
['alex', 'alex', 'alex', 'acd']

3.7 re.split(pattern, string[, maxsplit])函数

根据正则匹配分割字符串,返回分割后的一个列表

split(pattern, string, maxsplit=0, flags=0)

  • pattern: 正则模型
  • string : 要匹配的字符串
  • maxsplit:指定分割个数
  • flags : 匹配模式

按照一个字符将全部字符串进行分割

import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("a", origin)  # 根据正则匹配分割字符串
print(r)
['hello ', 'lex bcd ', 'lex lge ', 'lex ', 'cd 19']

将匹配到的字符串作为分割标准进行分割

import re
origin = "hello alex bcd alex lge alex 2acd 19"
r = re.split("a\w+", origin)  # 根据正则匹配分割字符串
print(r)
['hello ', ' bcd ', ' lge ', ' 2', ' 19']

3.8 re.sub(pattern, repl, string[, count])函数

替换匹配成功的指定位置字符串

sub(pattern, repl, string, count=0, flags=0)

  • pattern: 正则模型
  • repl : 要替换的字符串
  • string : 要匹配的字符串
  • count : 指定匹配个数
  • flags : 匹配模式
import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.sub("a", "替换", origin)  # 替换匹配成功的指定位置字符串
print(r)
hello 替换lex bcd 替换lex lge 替换lex 替换cd 19

3.9 re.subn(pattern, repl, string,[, count][, flags])函数

替换匹配成功的指定位置字符串,并且返回替换次数,可以用两个变量分别接受

subn(pattern, repl, string, count=0, flags=0)

  • pattern: 正则模型
  • repl : 要替换的字符串
  • string : 要匹配的字符串
  • count : 指定匹配个数
  • flags : 匹配模式
import re
origin = "hello alex bcd alex lge alex acd 19"
a, b = re.subn("a", "替换", origin)  # 替换匹配成功的指定位置字符串,并且返回替换次数,可以用两个变量分别接受
print(a)
print(b)
hello 替换lex bcd 替换lex lge 替换lex 替换cd 19
4

以上是关于081 re正则表达式模块的主要内容,如果未能解决你的问题,请参考以下文章

python正则表达式与re模块

python re模块 正则表达式

正则表达式与Python中re模块的使用

python——RE模块的基础应用及正则表达式的使用

7.17正则表达式与re模块

常用模块-正则re