通俗理解:
按照一定的规则,从某个字符串中匹配出想要的数据。这个规则就是正则表 达式。
官方参考:正则表达式
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 |
{} | 匹配括号内的表达式,也表示一个组 |
^: 指定匹配必须出现在字符串的开头或行的开头。
\A :指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。
$: 指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。
\Z: 指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。
更多参考: 正则教程
'''
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="(.*?)"','点击'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','点击'))#['href="http://www.baidu.com"']
'''
要理解?=和?!,?:,首先需要理解前瞻,后顾,负前瞻,负后顾四个概念:
// 前瞻:
exp1(?=exp2) 查找exp2前面的exp1
// 后顾:
(?<=exp2)exp1 查找exp2后面的exp1
// 负前瞻:
exp1(?!exp2) 查找后面不是exp2的exp1
// 负后顾:
(?
# |
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成’\’。
正则 | 待匹配字符 | 匹配 结果 | 说明 | |
---|---|---|---|---|
\n | \n | False | 因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配 | |
“\\n” | ‘\n’ | True | 在python中,字符串中的’‘也需要转义,所以每一个字符串’'又需要转义一次,转义\之后变成\,即可匹配 | |
r’\n’ | r’\n’ | True | 在字符串之前加r,让整个字符串不转义 |
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配。
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
# .* 默认为贪婪匹配,一直匹配到结尾最后一个值
print(re.findall('a.*b','a1b22222222b')) # 'a1b22222222b']
# .*? (固定格式) 为非贪婪匹配:推荐使用,匹配到字符串第一个值
print(re.findall('a.*?b', 'a1b22222222b')) #['a1b']
.*?的用法
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x
就是取前面任意长度的字符,直到一个x出现
正则 | 用途 | 待匹配字符串 | 匹配正则 |
---|---|---|---|
[] | 用来表示一组字符,单独列出 | 110101198001017032(身份证号码) | ^ \d{13,16}[0-9x]$ |
() | 匹配括号内表达式 | href=“http://www.baidu.com” (获取到网址) | href="(.*?)" |
import re
str1 = 'In 2020, I must learn Python!'
pattern = re.compile('\d+') # 如要反复重用,可以使用这种方法,将模式编译存在一个变量pattern中,便于重用
pattern.findall(str1) # ['2020']
import re
str1 = 'In 2020, I must learn Python! & @'
re.findall('\d+',str1) #临时使用,可以直接使用re下的方法:(模式,内容)
# ['2020']
函数名 | 描述 |
---|---|
re.compile(pattern,flags = 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) | 可以对文本(字符串)中所有可能被解释为正则运算符的字符进行转义的应用函数。 |
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)) # 以元组形式返回多个参数
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)) #
# 用search+^ 实现match的功能
print(re.search('^In', str1)) #
# 三:re.search的用法
# ===================================================
str1 = 'In 2020, I must learn Python! & @'
print(re.search('In', str1)) #
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)) # ,可调用的迭代器
for i in s:
print(i, end='\n')
'''
'''
# 五: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')) #
print(R_obj.match('123abc').group()) # 12
# 九 Match对象下的.group()方法
# ===================================================
R_obj = re.compile('\d{2}') # 正则对象
print(type(R_obj.match('123abc'))) #
print(R_obj.match('123abc').group()) # 12 ,str类型
# Match.group([ group1,... ] )
# 返回匹配项的一个或多个子组。如果有单个参数,则结果为单个字符串;如果有多个参数,则结果是一个元组,每个参数有一个项目。没有参数,group1默认为零(返回整个匹配项)。如果groupN参数为零,则对应的返回值是整个匹配字符串;否则,返回值为0。如果它在包含范围[1..99]中,则它是与相应括号组匹配的字符串。如果组号为负或大于模式中定义的组数,IndexError则会引发异常。如果组包含在部分不匹配的模式中,则对应的结果为None。如果在多次匹配的模式的一部分中包含一个组,则返回最后一个匹配项。
属性 | 别名 | 功能 |
---|---|---|
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())