Python必学模块之re模块(正则表达式)详解


一、什么是正则表达式

通俗理解:

按照一定的规则,从某个字符串中匹配出想要的数据。这个规则就是正则表 达式。

官方参考:正则表达式

二、re模块介绍

re模块是python独有的匹配字符串的模块,该模块中提供的很多功能是基于正则表达式实现的,而正则表达式是对字符串进行模糊匹配,提取自己需要的字符串部分,他对所有的语言都通用。注意:

  • re模块是python独有的
  • 正则表达式本质上是对字符串操作的逻辑公式,适用于所有程序语言。
  • re模块使python拥有全部的正则表达式功能

本章节主要介绍Python中常用的正则表达式处理函数。


三、常用正则表(元字符)

模式 描述
\w 匹配字母数字及下划线
\W 匹配 字母数字即下划线
\s 匹配任意 空白字符,等价于 [\t\n\r\f]
\S 匹配任意非空字符
\d 匹配任意数字,等价于 [0-9]
\D 匹配任意非数字
\A 匹配字符串开始
\z 匹配字符串结束
\Z 匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串
\G 匹配最后匹配完成的位置
\n 匹配一个换行符
\t 匹配一个制表符
^ 匹配字符串开头
$ 匹配字符串末尾
. 匹配任意字符,除了换行符,如果当re.DOTALL标记被指定时,则可以匹配包括换行符在内的任意字符
[…] 用来表示一组字符,单独列出:[abc] ,匹配"a",“b"或"c”
[^…] 不在[]中的字符:[ ^abc ] 匹配除了,a,b,c之外的字符
* 匹配0个或者多个的表达式
+ 匹配一个或者多个的表达式
? 匹配0个或者1个由前面的正则表达式定义的片段,非贪婪匹配
{n} 进准匹配n个前面的表达式
{n,m} 匹配n到m次由前面的正则表达式定义的片段,也叫贪婪方式
a|b 匹配a或者b
{} 匹配括号内的表达式,也表示一个组

3.1 \A,\z和^,$的区别

^: 指定匹配必须出现在字符串的开头或行的开头。

\A :指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。

$: 指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。

\Z: 指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。

更多参考正则教程

四、re模块用法示例

'''
re模块基础
Version:01
author:jasn
data:2020-04-16

'''
import re

# ==========================================================================================================================================
# 效果演示
str1 = 'In 2020, I must learn Python! & @'

#  \w:匹配数字字母及下划线
print(re.findall('\w',str1))
# 结果:['I', 'n', '2', '0', '2', '0', 'I', 'm', 'u', 's', 't', 'l', 'e', 'a', 'r', 'n', 'P', 'y', 't', 'h', 'o', 'n']

#  \W:匹配非字母数字及下划线
print(re.findall('\W', str1))
#  结果 :[' ', ',', ' ', ' ', ' ', ' ', '!', ' ', '&', ' ', '@']

#  \s匹配任意空白符
print(re.findall('\s',str1))
#  结果:[' ', ' ', ' ', ' ', ' ', ' ', ' ']

# \S 匹配任意非空字符
print(re.findall('\S', str1))
#  结果:['I', 'n', '2', '0', '2', '0', ',', 'I', 'm', 'u', 's', 't', 'l', 'e', 'a', 'r', 'n', 'P', 'y', 't', 'h', 'o', 'n', '!', '&', '@']

# \d 匹配任意数字,等价于[0-9]
print(re.findall('\d', str1))
print(re.findall('[0-9]', str1))   # 结果相同
# 结果:['2', '0', '2', '0']

# 、\D 匹配任意非数字
print(re.findall('\D', str1))
# 结果 :['I', 'n', ' ', ',', ' ', 'I', ' ', 'm', 'u', 's', 't', ' ', 'l', 'e', 'a', 'r', 'n', ' ', 'P', 'y', 't', 'h', 'o', 'n', '!', ' ', '&', ' ', '@']

# A 匹配字符串的开始 ;\Z匹配字符串的结束,有返回匹配的值,无返回空
print(re.findall('\AIn', str1))  # ['In'],\A  ==>   ^
print(re.findall('@\Z', str1))  # ['@'],\Z  ==>  $

# ^ 匹配字符串的开头;$匹配字符串的结束
print(re.findall('^I', str1))   # ['I']
print(re.findall('@$', str1))   # ['@']

'''
\A,\Z 和 $ ^ 的区别:

^: 指定匹配必须出现在字符串的开头或行的开头。

\A :指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。

$:  指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。

\Z: 指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。
'''

# ===========================================================================================================================================
# 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
# ===========================================================================================================================================
# . 匹配任意字符,除换行符外

print(re.findall('a.b','a1b'))  # ['a1b']
print(re.findall('a.b','a1b a*b a b aaab'))  # ['a1b', 'a*b', 'a b', 'aab']
print(re.findall('a.b','a\nb'))  # []
print(re.findall('a.b','a\nb', re.S))  # ['a\nb']

# 如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始。
# 而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,在整体中进行匹配。

print(re.findall('a.b','a\nb',re.DOTALL))  # ['a\nb']同上一条意思一样
# re.DOTALL。这使得正则表达式中的句点(.)可以匹配所有的字符,也包括换行符

#  * 匹配*左侧字符 一个或者 多个
print(re.findall('ab*','bbbbbbb'))  # []
print(re.findall('ab*','a'))  # ['a']
print(re.findall('ab*','abbbb'))  # ['abbbb']

# ? 匹配前面的子表达式 0 次或 1 次(等价于{0,1})
print(re.findall('ab?','a'))  # ['a']
print(re.findall('ab?','abbb'))  # ['ab']

# 匹配所有包含小数在内的数字
print(re.findall('\d+[.]?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) # ['123', '1.13', '12', '1', '3']


# .*  默认为贪婪匹配,一直匹配到结尾最后一个值
print(re.findall('a.*b','a1b22222222b'))  # 'a1b22222222b']

#  .*? (固定格式) 为非贪婪匹配:推荐使用,匹配到字符串第一个值
print(re.findall('a.*?b', 'a1b22222222b')) #['a1b']

# +  匹配前面的子表达式 1 次或多次(等价于{1, })
print(re.findall('ab','a'))  # []
print(re.findall('ab+','abbb'))  # ['abbb']

# {n,m}  m 和 n 均为非负整数,其中 n <= m,最少匹配 n 次且最多匹配 m 次
print(re.findall('ab{2}','abbb'))  # ['abb'] 匹配2个b
print(re.findall('ab{2,4}','abbbbbb'))  # ['abbbb'] 最少匹配2个,最多匹配4个
print(re.findall('ab{1,}','abbb'))  # 'ab{1,}' ===> 'ab+' 匹配1个到无穷个

print(re.findall('ab{0,}','abbb'))  # 'ab{0,}' ===> 'ab*' 匹配0个到无穷个


# ==============================================================================================================================================
# [] 用来表示一组字符,单独列出
print(re.findall('a[1*-]b', 'a1b a*b a-b'))  # []内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
print(re.findall('a[^1*-]b', 'a1b a*b a-b a=b'))   # []内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[0-9]b', 'a1b a*b a-b a=b'))  # []内代表匹配任意0-9之间的值
print(re.findall('a[a-z]b', 'a1b a*b a-b a=b aeb'))  # []内代表匹配任意a-z之间的值
print(re.findall('a[a-zA-Z]b', 'a1b a*b a-b a=b aeb aEb'))  # []内代表匹配任意a-z和A-Z之间的值

# \
# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
print(re.findall('a\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c']

# ===============================================================================================================================================

#():分组 匹配括号内表达式,也是一个分组
print(re.findall('ab+','ababab123'))  # ['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123'))  # ['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123'))  # findall的结果不是匹配的全部内容,而是组内的内容, ?: (固定写法)  可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>'))#['href="http://www.baidu.com"']

'''
要理解?=和?!,?:,首先需要理解前瞻,后顾,负前瞻,负后顾四个概念:

// 前瞻:
exp1(?=exp2) 查找exp2前面的exp1
// 后顾:
(?<=exp2)exp1 查找exp2后面的exp1
// 负前瞻:
exp1(?!exp2) 查找后面不是exp2的exp1
// 负后顾:
(?<!exp2)exp1 查找前面不是exp2的exp1

(?:exp2) 匹配字符串中所有的exp2

'''

# |
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))

4.1 转义字符

在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成’\’。

正则 待匹配字符 匹配 结果 说明
\n \n False 因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
“\\n” ‘\n’ True 在python中,字符串中的’‘也需要转义,所以每一个字符串’'又需要转义一次,转义\之后变成\,即可匹配
r’\n’ r’\n’ True 在字符串之前加r,让整个字符串不转义

4.2 贪婪匹配和非贪婪匹配

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配。

加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串

# .*  默认为贪婪匹配,一直匹配到结尾最后一个值
print(re.findall('a.*b','a1b22222222b'))  # 'a1b22222222b']

#  .*? (固定格式) 为非贪婪匹配:推荐使用,匹配到字符串第一个值
print(re.findall('a.*?b', 'a1b22222222b')) #['a1b']

.*?的用法

. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。

何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x

就是取前面任意长度的字符,直到一个x出现

4.3 字符集[]和分组()的区别

正则 用途 待匹配字符串 匹配正则
[] 用来表示一组字符,单独列出 110101198001017032(身份证号码) ^ \d{13,16}[0-9x]$
() 匹配括号内表达式 href=“http://www.baidu.com” (获取到网址) href="(.*?)"

五、re模块的使用

5.1 赋值变量重用

import re
str1 = 'In 2020, I must learn Python!'
pattern = re.compile('\d+')  # 如要反复重用,可以使用这种方法,将模式编译存在一个变量pattern中,便于重用
pattern.findall(str1)  # ['2020']

5.2 直接使用

import re
str1 = 'In 2020, I must learn Python! & @'
re.findall('\d+',str1)  #临时使用,可以直接使用re下的方法:(模式,内容)
# ['2020']

六、re模块常用函数

6.1 常用函数功能简介

函数名 描述
re.compile(patternflags = 0 将正则表达式模式编译成正则表达式对象
findall(pattern,string,flags = 0 ) 以string列表形式返回string中pattern的所有非重叠匹配项。从左到右扫描该字符串,并以找到的顺序返回匹配项。如果该模式中存在一个或多个组,则返回一个组列表;否则,返回一个列表。如果模式包含多个组,则这将是一个元组列表。空匹配项包含在结果中。
re.match(pattern,string,flags = 0 ) 从一个字符串的开始位置起匹配正则表达式,返回 match 对象,可以用search+^代替match
re.search(pattern,string,flags = 0 ) 会在字符串内查找模式匹配,直到找到第一个匹配然后返回 match 对象,如果字符串没有匹配,则返回None
re.finditer(pattern, string, flags=0) 返回的是一个迭代器,每个迭代元素是 match 对象。
re.sub(pattern,repl,string,count = 0,flags = 0 ) 用于替换字符串中的匹配项,返回通过用替换repl替换字符串中最左边的不重叠模式所获得的字符串。如果找不到该模式, 则返回的字符串不变。repl可以是字符串或函数;如果是字符串,则处理其中的任何反斜杠转义。即,将其转换为单个换行符,将其转换为回车,依此类推。count参数表示将匹配到的内容进行替换的次数。
re.split(pattern,string,maxsplit = 0,flags = 0 ) 通过出现模式来拆分字符串。如果在pattern中使用了捕获括号,那么模式中所有组的文本也将作为结果列表的一部分返回。如果maxsplit不为零,则最多会发生maxsplit分割,并将字符串的其余部分作为列表的最后一个元素返回。
re.escape(pattern) 可以对文本(字符串)中所有可能被解释为正则运算符的字符进行转义的应用函数。

6.2 re.Match对象下的方法和属性

re.Match对象的方法

方法 描述
.group() 返回匹配项的一个或多个子组。如果有单个参数,则结果为单个字符串;如果有多个参数,则结果是一个元组,每个参数有一个项目。没有参数,group1默认为零(返回整个匹配项)。如果groupN参数为零,则对应的返回值是整个匹配字符串;否则,返回值为0。
.start() 匹配字符串在原始字符串的开始位置
.end() 匹配字符串在原始字符串的结束位置
.span() 返回(.start(), .end())
.groups() 返回一个包含匹配项所有子组的元组,如果没有则返回None

re.Match对象的属性

属性 描述
.string 待匹配的文本
.re 匹配时使用的 pattern 对象(正则表达式)
.pos 正则表达式搜索文本的开始位置
.endpos 正则表达式搜索文本的结束位置

代码实例

import re
text = "apple price is $99,orange price is $88"
result = re.search('.+(\$\d+).+(\$\d+)',text)
print(result)

# groups()的 用法
# ===================================================
print(result.groups())


# group()的 用法
# ===================================================
print(result.group())   # 整个匹配
print(result.group(1))  # 第一个括号内的子组
print(result.group(2))  # 第二个括号内的子组
print(result.group(1, 2))  # 以元组形式返回多个参数


6.3 常用函数代码实例

import re

# 一:findall的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'

#  \w:匹配数字[0-9]
print(re.findall('\d',str1))  # 结果:['2', '0', '2', '0']


# 二:re.match的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'

print(re.match('a', str1))   # 如果字符串开头匹配不到,则返回None
print(re.match('In', str1))  # <re.Match object; span=(0, 2), match='In'>
# 用search+^ 实现match的功能
print(re.search('^In', str1))  # <re.Match object; span=(0, 2), match='In'>


# 三:re.search的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'

print(re.search('In', str1))  # <re.Match object; span=(0, 2), match='In'>
print(re.search('e', str1).group())  # e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None


# 四:re.finditer的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
s = re.finditer('\d', str1)
print(type(s))  # <class 'callable_iterator'> ,可调用的迭代器
for i in s:
    print(i, end='\n')
'''
<re.Match object; span=(3, 4), match='2'>
<re.Match object; span=(4, 5), match='0'>
<re.Match object; span=(5, 6), match='2'>
<re.Match object; span=(6, 7), match='0'>
'''


# 五:re.sub的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.sub('C语言', 'java', str1))  # 如果找不到,则返回字符串不变 In 2020, I must learn Python! & @
print(re.sub('Python', 'java', str1))  # In 2020, I must learn java! & @

print(re.sub('0', '1', str1,))  # 默认将所有的0,替换为1
print(re.sub('0', '1', str1, 1))  # 长度选 1,只替换从左到右第一个0



# 六:re.split的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.split('n', str1))  # 默认以所有n的位置来分割,返回结果不包含分隔符
print(re.split('n', str1, 2))  # 以字符串从左到右顺序分割前两个n,返回结果不包含分隔符
print(re.split('(n)', str1,))  # 若将分隔符加入group,那么返回结果中也包括分隔符



# 七:re.escape(pattern)方法
# ===================================================
blog_url = 'https://blog.csdn.net/weixin_42444693'
print(re.escape(blog_url))  # 将文本(字符串)中所有可能被解释为正则运算符的字符进行转义的应用函数。



# 八:re.compile(pattern,flags = 0)方法
# ===================================================
R_obj = re.compile('\d{2}')  # 正则对象
print(R_obj.search('12abc').group())  # 12  通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。


print(R_obj.match('123abc'))  # <re.Match object; span=(0, 1), match='12'>
print(R_obj.match('123abc').group())  # 12



# 九 Match对象下的.group()方法
# ===================================================
R_obj = re.compile('\d{2}')  # 正则对象
print(type(R_obj.match('123abc')))  #  <class 're.Match'>
print(R_obj.match('123abc').group())  #   12 ,str类型

# Match.group([ group1,... ] )
# 返回匹配项的一个或多个子组。如果有单个参数,则结果为单个字符串;如果有多个参数,则结果是一个元组,每个参数有一个项目。没有参数,group1默认为零(返回整个匹配项)。如果groupN参数为零,则对应的返回值是整个匹配字符串;否则,返回值为0。如果它在包含范围[1..99]中,则它是与相应括号组匹配的字符串。如果组号为负或大于模式中定义的组数,IndexError则会引发异常。如果组包含在部分不匹配的模式中,则对应的结果为None。如果在多次匹配的模式的一部分中包含一个组,则返回最后一个匹配项。

七、re模块的常量(属性)

属性 别名 功能
re.A re.ASCII 让\w,\W,\b,\B,\d,\D,\s和\S 执行ASCII-只匹配完整的Unicode匹配代替。这仅对Unicode模式有意义,而对于字节模式则忽略。
re.I re.IGNORECASE 执行不区分大小写的匹配;类似的表达式也[A-Z]将匹配小写字母。
re.L re.LOCALE 让\w,\W,\b,\B和区分大小写的匹配取决于当前的语言环境。该标志只能与字节模式一起使用。不建议使用此标志,因为语言环境机制非常不可靠,它一次只能处理一种“区域性”,并且仅适用于8位语言环境。默认情况下,Python 3中已为Unicode(str)模式启用了Unicode匹配,并且能够处理不同的语言环境/语言。
re.M re.MULTILINE 指定时,模式字符’^‘在字符串的开头和每行的开头(紧随每个换行符之后)匹配;模式字符’KaTeX parse error: Expected group after '^' at position 37: …行符之前)匹配。默认情况下,'^̲' 仅在字符串的开头,字符串''的末尾和字符串末尾的换行符(如果有)之前立即匹配。
re.S re.DOTALL 使 ‘.’ 特殊字符与任何字符都匹配,包括换行符;没有此标志,’.’ 将匹配除换行符以外的任何内容。

八、练习题

import re

# 1. 验证手机号码:手机号码的规则是以1开头,第二位可以是34587,后面那9位就可以随意了。

text = "18677889900"
result = re.match("1[34587]\d{9}",text)
print(result.group())


# 2. 验证邮箱:邮箱的规则是邮箱名称是用数字、英文字符、下划线组成的,然后是@符号,后面就是域名了。
text = "[email protected]"
result = re.match("\w+@[a-z0-9]+\.[a-z]+",text)
print(result.group())


# 3. 验证URL:URL的规则是前面是http或者https或者是ftp然后再加上一个冒号,再加上一个斜杠,再后面就是可以出现任意非空白字符了。
text = "https://blog.csdn.net/weixin_42444693"
result = re.match("(http|https|ftp)://\S+",text)
print(result.group())

发布了81 篇原创文章 · 获赞 105 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42444693/article/details/105579613