正则表达式超详细理解

学习正则表达式有几天了,今天跟大家分享一下我对python中关于正则表达式的理解。文章可能过于繁琐、篇幅过长,有不足之处烦请各位大佬帮忙斧正

什么是正则表达式?

通俗的理解就是按照一定的规则,从某一个字符串中匹配出我们想要得到的数据。而这个规则就是正则表达式。
点我看官方理解.

为什么要学正则表达式?

1.可以判断一些数据是不是符合我们的需要

2.从网上down一些数据的时候 来设定符合自己意向的一些数据

关于re模块

Python通过标准库re模块来支持正则表达式,通过这个模块就可以使 Python 拥有全部的正则表达式功能,使用之前我们需要导入re模块

import re

关于转义字符串和原生字符串

在正则表达式中,有些字符是具有特殊意义的字符, 因此想要匹配到这些字符,就必须使用反斜杠进行转义字符串。比如’$‘符号代表的是以…结尾(下面会说它的用法),如果想要匹配’$‘符号,把它当作普通字符,就必须在前面加一个 \ , 即’\$’

string = "The apple price is $20"
ret = re.search("\$\d+", string)
print(ret.group())

结果-->
$20

原生字符串:
在正则表达式中,\ 是专门用来做转义的。在Python中 \ 也是用来做转义的。

python语言中的原生字符串

例如 text = "\n" 是换行符 如果我们想要打印出"\n" 就得在它前面加一个 \
即"\\n" 它的意思就是 第一个 \ 是转义, 把第二个 \ 的特殊意义去掉,
然后两个\ 合成一个\, 变成'\n', 再打印就是\n 了。
即 \\n 等价于 \n

也可以写成 text = r"\n", 这个就表示原生字符串,
 即对双引号里面的东西不做任何的处理, 里面是什么就是什么。 
即前面加 r 的都是原生字符串

python语言的原生字符串和正则表达式结合起来
因此如果想要在普通的字符串中匹配出 \ ,那么要给出四个 \ ,代码如下

string = "Hello \Python"
ret = re.search("Hello \\\\Python", string)
print(ret.group())

结果-->
Hello \Python

为什么是四个\???
首先在python中把前面两个\\ 和成一个\
再把后面的两个\\和成一个\ 变成 \\Python
然后再把\\Python扔给正则表达式,正则表达式再进行转义一下,把两个\合成一个\
变成\Python,就可以匹配出\Python了

给的 \ 太多也不是很方便,因此我们使用原生字符串就可以解决这个问题,代码如下

string = "Hello \Python"
ret = re.search(r"Hello \\Python", string)
print(ret.group())

结果-->
Hello \Python

result = re.match(正则表达式,要匹配的字符串)

这个方法的特点是从我们要匹配的字符串的开头开始匹配,一直向后进行匹配,如果遇到无法匹配的字符或者是匹配不到我们想要的结果它会返回一个None值。如果匹配成功会返回一个Match,并且终止匹配,不会再继续向后面匹配下去,我们通过group来提取数据,下面分别对两种情况进行演示

1.匹配到数据

import re
string = "123456"
result = re.match(r"\d", string)
print(type(result))
print(result == None)	# 看它是不是None
print(result.group())

# 结果
<class 're.Match'>
False

2.没有匹配到数据

string = "123456"
result = re.match(r"abc", string)

"""或者
string = "abc123456"
result = re.match("123", string)   # 这种就是开头遇见了无法匹配的字符
"""
print(type(result))
print(result == None)

""" 注意
如果这时我们再 print(result.group()) 会报错, 因为这时没有匹配到数据,
只有匹配到数据的时候我们才用group提取数据	
"""

# 结果
<class 'NoneType'>
True

正则表达式的单字符匹配

所谓单字符匹配就是一次只能匹配一个字符(这话打出来要挨打)

"""
字符			功能
.			匹配任意一个字符(\n除外)
[]			匹配[]中列举的字符
\d			匹配数组,即0-9
\D   		匹配非数字,即不是数字
\s			匹配空白,即空格,tab键
\S 			匹配非空白符
\w   		匹配单词字符,即a-z,A-Z,0-9, _
\W 			匹配非单词字符
"""
1. \d的使用–>匹配数字,即0-9
string = "123456"
result = re.match(r"\d", string)
print(result.group())
结果-->
1
# 想要匹配两个就再后面在加一个\d
result = re.match(r"\d\d", string)
print(result.group())
结果-->
12
2. \D的使用–>匹配非数字,即不是数字
string = "abc123"
result = re.match(r"\D", string)
print(result.group())
结果-->
a
3. \s的使用–>匹配空白符,即空格,tab键
print(re.match(r"速度与激情\s\d","速度与激情 0").group())
print(re.match(r"速度与激情\s\d","速度与激情\t0").group())

结果-->
速度与激情 0
速度与激情	0
4. \S的使用–>匹配非空白符
print(re.match(r"速度与激情\S", "速度与激情好").group())
print(re.match(r"速度与激情\S", "速度与激情=").group())
print(re.match(r"速度与激情\S", "速度与激情1").group())

结果-->
速度与激情好
速度与激情=
速度与激情1
5. \w的使用–>匹配单词字符,即a-z,A-Z,0-9, _
print(re.match(r"速度与激情\w", "速度与激情a").group())
print(re.match(r"速度与激情\w", "速度与激情A").group())
print(re.match(r"速度与激情\w", "速度与激情0").group())
print(re.match(r"速度与激情\w", "速度与激情_").group())

结果-->
速度与激情a
速度与激情A
速度与激情0
速度与激情_
7. \W的使用–>匹配非单词字符(\w能匹配的,\W都不能匹配)
print(re.match(r"速度与激情\W", "速度与激情=").group())
print(re.match(r"速度与激情\W", "速度与激情?").group())
print(re.match(r"速度与激情\W", "速度与激情#").group())

结果-->
速度与激情=
速度与激情?
速度与激情#
8. [](中括号)–>匹配[]中列举的字符

如果想要列举好几个范围中间不要加任何东西

print(re.match(r"[H]ello", "Hello world").group())
print(re.match(r"[hH]ello", "Hello world").group())
print(re.match(r"速度与激情[1-36-8]", "速度与激情2").group())
print(re.match(r"速度与激情[1-8]", "速度与激情8").group())
print(re.match(r"速度与激情[a-zA-Z0-9]","速度与激情c").group())
print(re.match(r"速度与激情[a-zA-B0-9]","速度与激情A").group())

结果-->
Hello
Hello
速度与激情2
速度与激情8
速度与激情c
速度与激情A
9.!!! .(点)的使用–>匹配任意一个字符(\n除外)
print(re.match(r"速度与激情.","速度与激情=").group())
print(re.match(r"速度与激情.","速度与激情!").group())
print(re.match(r"速度与激情.","速度与激情哈").group())
print(re.match(r"速度与激情.","速度与激情1").group())
print(re.match(r"速度与激情.","速度与激情^").group())

# print(re.match(r"速度与激情.","速度与激情\n").group()) 匹配不到

结果-->
速度与激情=
速度与激情!
速度与激情哈
速度与激情1
速度与激情^

正则表达式的多字符匹配

"""
字符			功能
*			匹配前一个字符出现0次或者无限次,可有可无
+			匹配前一个字符出现1次或者无限次,即至少出现一次
?			匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m}			匹配前一个字符出现m次
{m,n}		匹配前一个字符出现从m到n次
"""
10. {m,n}的使用–>匹配前一个字符出现从m到n次, 它会匹配最大长度
# {}可以约束前面和它紧挨着的位数
print(re.match(r"速度与激情\d{1,2}","速度与激情12").group()) # 位数从1-2
print(re.match(r"速度与激情\d{1,3}","速度与激情123").group())# 位数从1-3 可以是一位、两位、三位
print(re.match(r"速度与激情\d{1,3}","速度与激情12").group())
print(re.match(r"速度与激情\d{1,7}","速度与激情1235").group())  # 位数从1-7

结果-->
速度与激情12
速度与激情123
速度与激情12
速度与激情1235
11. {m}的使用–>匹配前一个字符出现m次
# {}限定必须有多少位,且必须是连续的 比如输入手机号码
print(re.match(r"\d{11}","12345678910").group())
print(re.match(r"\d{11}","123411678910").group()) # 如果字符串超过限制会取前面的位数, 会取前11位

结果-->
12345678910
12341167891
12.?的使用–>匹配前一个字符出现1次或者0次, (有就只有一次, 没有就没有)
print(re.match(r"\d{3}-?\d{8}","021-12345678").group())
print(re.match(r"\d{3}-?\d{8}","02112345678").group())
print(re.match(r"\d{3,4}-?\d{8}","02112345678").group())

# \d{3} 匹配数字三位, -? 这个'-'可有可无, \d{8}匹配数字8位

"""
print(re.match(r"\d{3}--?\d{8}","021-12345678").group())
对于这个式子, 第一个'-'在匹配的串中有, 第二个'-'串中没有,结果也是
021-12345678
"""

结果-->
021-12345678
02112345678
0211
13. * 的使用–>匹配前一个字符出现0次或者无限次,可有可无
print(re.match(r"\d*-?\d*","021-12345678").group())
print(re.match(r"\d*-?\d*","1-").group())
print(re.match(r"\d*-?\d*","-").group())
print(re.match(r"\d*-?\d*","-1").group())

# \d* 数字0位或者多位, -? 这个'-'可有可无

结果-->
021-12345678
1-
-
-1
14. .*的使用

匹配任意字符0位或者多位 但是不会匹配到\n换行符, 如果想要匹配换行符再表达式后面加一个re.S, 并且打印的时候会把换行符打印出来

html_content = """asdad\nasfkaso\nagagnoai\nsogahoshfi\npsiufhsIPD\nG\niSG"""
print(re.match(r".*",html_content).group()) # 只会显示asdad  .不会匹配\n
print(re.match(r".*",html_content,re.S).group()) # re.S 能够匹配到\n
print(re.match(r".*","").group())
结果-->
第一组打印数据
asdad
第二组打印数据
asdad
asfkaso
agagnoai
sogahoshfi
psiufhsIPD
G
iSG
第三组打印数据 一个空白符

15. .+的使用–>匹配至少一个符号
print(re.match(r".+","a").group())	# ok
print(re.match(r".+","ab12=-=").group()) # ok
print(re.match(r".+","aashfoaihf0ha0shf0127rhOASIH[o").group()) # ok

结果-->
a
ab12=-=
aashfoaihf0ha0shf0127rhOASIH[o

注意 (.*)和(.+)的区别, 看代码

print(re.match(r".*","").group()) ### 可以
print(re.match(r".+","").group()) ### 错

print("---->",re.match(r"[\w]*","#").group()) ###  可以
print("---->",re.match(r"[\w]+","#").group())  ###  错

也就是说, '.*' 前面的字符可以匹配成功也可以没有匹配成功,
 但是用'.+'就表示前面的字符必须要匹配到一个

匹配开头结尾

"""
字符			功能
^			匹配字符串开头			match自带判断开头
$			匹配字符串结尾 
"""
16. 下面通过一个小栗子来介绍这两个功能
names = ["name1","_name","name#","2_name","__name__","a#123","?name__","[]name_","a#123","abc!"]

for name in names:
	ret = re.match(r"^[a-zA-Z_]+[\w]*$",name)
	# 这里匹配的规则是:	
	# 至少有一个以a-z或者A-Z或者'_'开头的字符。中间的可以匹配[a-zA-Z_0-9]其中的0个或者多个。并且以[a-zA-Z_0-9]其中的结尾的
	if ret:
		print("变量名:%s 符合要求,通过正则表达式匹配出来的是:%s"% (name,ret.group()))
	else:
		print("变量名:%s 不符合要求"%name)

结果-->
变量名:name1 符合要求,通过正则表达式匹配出来的是:name1
变量名:_name 符合要求,通过正则表达式匹配出来的是:_name
变量名:name# 不符合要求
变量名:2_name 不符合要求
变量名:__name__ 符合要求,通过正则表达式匹配出来的是:__name__
变量名:a#123 不符合要求
变量名:?name__ 不符合要求
变量名:[]name_ 不符合要求
变量名:a#123 不符合要求
变量名:abc! 不符合要求

匹配分组

|				匹配左右任意一个表达式
(ab)			将括号中字符作为一个分组

如果在正则表达式中,这个条件匹配出来的字符串也成,那个条件匹配出来的字符串成立也成,那我们可以使用 | 这个符号, 例如, re.match(r"a|b", “abc”) 这个式子,匹配到a也行,匹配到b也行。如果要匹配的字符串是"abc",会匹配到 a。如果要匹配的字符串是"bc"会匹配到 b 。

# 这个匹配的规则是 匹配到[a-zA-Z0-9_]{4,20}@163也行, 匹配到126\.com$也行。
print(re.match(r"^[a-zA-Z0-9_]{4,20}@163|126\.com$", "xx121@163").group())
print(re.match(r"^[a-zA-Z0-9_]{4,20}@163|126\.com$", "126.com").group())
#结果-->
xx121@163
126.com


# 这个匹配的规则是以[a-zA-Z0-9_]开头4-20位,接下来要匹配到 @ 符号,后面的可以是163,可以是126可以是qq
# 也可以是sina, 并以com结尾。
print(re.match(r"^[a-zA-Z0-9_]{4,20}@(163|126|qq|sina)\.com$","xx121@163.com").group())
print(re.match(r"^[a-zA-Z0-9_]{4,20}@(163|126|qq|sina)\.com$","xx121@163.com").group())

结果-->
xx121@163.com
xx121@163.com

()还可以取出里面的值

  1. 如果我们只想要字符串中的某一部分,就把想要的那一部分加上括号,通过group(数字),提取出来。
    group(1) 是提取正则表达式中第一个加括号的部分,如果有多个括号的前提下,想提取第二个括号、第三个括号…就相应的在group()括号中填上对应的数字。

  2. 也可以给group传多个参数,提取多个括号里面的内容。例如:在正则表达式中有至少3个括号的前提下,group(1,2,3)对应第一个括号里面的,第二个括号里面的, 第三个括号里面的。打印出来就是前三个括号匹配到的数据。

# 取出@前面的值
print(re.match(r"^([a-zA-Z0-9_]{4,20})@(163|126|qq|sina)\.com$","xx121@126.com").group(1))
# 取出126				 
print(re.match(r"^[a-zA-Z0-9_]{4,20}@(163|126|qq|sina)\.com$","xx121@126.com").group(1))
									
									


关于re.match和re.search和re.findall的区别

re.match: 从头开始匹配, 开头有详细的解释。
re.search: search 不用从头开始匹配 只要正则成功就会返回一个值,停止匹配。

ret = re.search(r"\d+","阅读123次数为: 9999") # 匹配到123就停止匹配了  后面的9999不会匹配
print(ret.group())	----->>>> 123

re.findall: 找出所有符合条件的字符串并且返回一个列表。在打印的时候我们不需要再加上group了。

# 匹配的规则是找出字符串中的所有的数字
ret1 =re.findall(r"\d+","阅读123次数为: 9999,点赞数为:12345")# 返回的是一个列表 不需要group了
print(ret1) --->>>> [123,9999,12345]

re.sub的使用

sub 将匹配到的东西换成新的东西 然后返回整个字符串 并且他支持一个函数的调用
re.sub(正则表达式, 新的东西, 要替换的东西)
# 匹配规则是 找出字符串中的所有数字, 并把他们替换成新的东西
# 第三个样例中,add是一个函数的引用,表示将字符串中的数字都加1
print(re.sub(r"\d+","123","python=456,c++=789"))
print(re.sub(r"\d+","abc","python=456,c++=789"))
print(re.sub(r"\d+",add,"python=456,c++=789"))	# 数字都 + 1


结果-->
python=123, c++=123
python=abc, c++=abc
python=457, c++=790

re.split的使用

re.split(正则表达式, 要切割的字符串) 结果并返回一个列表
split_str = "xiaohuolong:@ qq .com :123123"
# 以冒号分割或者是以空格分割
ret2 = re.split(r":| ",split_str)	
print(ret2)

结果-->
['xiaohuolong', '@', 'qq', '.com', '', '123123']

关于python中正则表达式用到的内容到此差不多都有了,写完这么多真心不容易 如果有什么遗漏的地方请各位大佬帮忙斧正。

  • 59
    点赞
  • 199
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值