正则表达式是干什么的
使用正则表达式就是为了从一大串子字符串中获取你想要的那部分,如果你明确的知道你想要的就是字符串"wjg946"那么就不需要使用一些高级的匹配用法,其实如果你知道了你想要的字符串就是"wjg946"那还匹配什么,所一般都是只知道所需字符串的部分特征,要做的就是根据这些特征把想要的字符串从大量文本中揪出来。
python中使用正则表达式一般都是使用re库,所以写这个。
基本知识
1、匹配规则
d w s
. | 匹配任意1个字符(除了换行符\n) |
---|---|
[ ] | 匹配 [ ] 中列举的字符 |
\d | 匹配数字,也就是0-9 |
\D | 匹配非数字,也就是匹配不是数字的字符 |
\s | 匹配空白符,也就是 空格、换行符、制表符 |
\S | 匹配非空白符 |
\w | 匹配单词字符, a-z, A-Z, 0-9, _也就是字母、数字、下划线 |
\W | 匹配非单词字符 |
2、匹配数量规则
* | 匹配前一个字符出现0次多次或者无限次,可有可无,可多可少 |
---|---|
+ | 匹配前一个字符出现1次或则无限次 |
? | 匹配前一个字符出现1次或者0次 |
{m} | 匹配前一个字符出现m次 |
{m,} | 匹配前一个字符至少出现m次 |
{m,n} | 匹配前一个字符出现m到n次 |
3、限定匹配的位置
^ | 匹配字符串开头 |
---|---|
$ | 匹配字符串结尾 |
^意味着这个字符串必须从开头就开始满足匹配条件,不然整个字符串后面的就看了,
$同理
^和$同时使用意味着整个字符串必须匹配该模式,只匹配字符串的某个子集是不够的。
regex =re.compile(r"^hi$")
regex.search("hi").group()
#hi
regex.search("hih").group()
#None
4、建立自己的字符分类
有时候\d \s \w范围太广了,需要自己定义一个就可以使用[ ],代表一个字符,当某个字符属于括号里面的某一个就符合,如果是[^ ]就是不包括里面的,即剔除。
regex =re.compile(r"[123]+")
regex.search("237123").group()
#'23'
regex =re.compile(r"[123]{3}")
regex.search("237123").group()
#'123'
regex =re.compile(r"[^123]+")
regex.search("237123").group()
#'7'
还可以写[A-Za-z0-9]
常用函数
1、re.compile()
传入一个字符串,作为正则表达式,返回一个Regex对象(就是Regex模式、匹配模式)。
2、Regex.search()
向匹配模式中传入一个需要查找的字符串,在该字符串中寻找符合条件的所有匹配,如果没有,返回None。返回的对象类型是Match
3、Match.group()
Match.group()返回实际匹配的字符串文本。
import re
regex = re.compile(r"\d{11}")
match = regex.search("我的电话号码是17854339997")
result = match.group()
print(result)
#17854339997
高级用法:
1、分组
如果想要将匹配到的字符串分成几个部分,分别取出来,就需要在构造匹配模式的时候使用括号创建分组。
然后在match.group()中传入参数,0或者不传参代表返回整个文本,1对应第一组,2对应第二组
import re
regex = re.compile(r"(\d{3})(\d{8})")
match = regex.search("我的电话号码是17854339997")
if match:#避免没有找到,返回None,也会执行
result = match.group(1)
print(result)
else:
print("NOT FOUND")
#178
2、用管道同时生成多种匹配模式
字符|称为管道,在构造匹配模式时,可以同时生成多个,在匹配字符串时,只要妈祖多个匹配模式中的一种即可,但是search()只会返回一个Match对象,里面只有一个满足条件的字符串,前面说的分组,是在这一个字符串的进一步分组。
import re
regex = re.compile(r"(\d{3})(\d{8})|电话")
match = regex.search("我的电话号码是17854339997")
if match:#避免没有找到,返回None,也会执行
result = match.group()
print(result)
else:
print("NOT FOUND")
#电话
3、贪心匹配和非贪心匹配
在hihihihihi字符串中,(hi)+可以把整个字符串都匹配到,这就是贪心匹配,再对比非贪心匹配,非贪心匹配会得到hi一个就够了,匹配模式是(hi)?
所谓贪心与非贪心只是针对一些可以匹配到多个的情况,例如 **+ 和 * 和 {1,9}**这几个默认都是贪心的,变成非贪心就只需要在后面加一个问号?
regex_tan = re.compile(r"(hi)+")
regex_butan = re.compile(r"(hi)+?")
match_tan = regex_tan.search("hihihihihi")
print(match_tan.group())
#hihihihihi
match_butan = regex_butan.search("hihihihihi")
print(match_butan.group())
#hi
如果匹配模式写的是(hi)*?那么由于非贪婪,这个正则表达式会匹配到空字符串,但也不是None
4、regex.findall()
regex.search()只能从字符串中找出一个匹配对象,而这个regex.findall()可以匹配到字符串中所有满足要求的。但是与前者不同的地方是,findall()返回的是字符串列表而不是match对象,所以也就不能使用group()方法,因为group()对于分组之后取第几组比较友好,那么对于findall()中分组的情况该怎么解决呢?如果匹配模式进行了分组,那么findall()返回的就是元组的列表。
regex = re.compile(r"(\d{3})(\d{8})")
l = regex.findall("我的电话是17856786533,小虎的电话是18892736300")
if l:
print(l)
#[('178', '56786533'), ('188', '92736300')]
5、.*可以匹配任何长度的字符(换行符处会截断),.*?就是一种很好的承接后面部分的东西(不好解释),如果让.也可以匹配换行符,需要在compile()函数后面跟上一个re.DOTALL
noNewLineRegex = re.compile(r".*")
noNewLineRegex.search("Hello\nHow are you?").group()
#'Hello'
newLineRegex = re.compile(r".*",re.DOTALL)# .可以匹配换行符了
newLineRegex.search("Hello\nHow are you?").group()
#'Hello\nHow are you?'
6、不区分大小写的匹配
向re.compile()中传入re.I或者re.IGNORECASE可以不区分大写来匹配
regex = re.compile(r"hello",re.I)
regex.search("HELLO\nHow are you?").group()
#'HELLO'
匹配演示
注意区别
regex = re.compile(r"[^电话]")
l = regex.findall("我的电话是17856786533,小虎的电话是18892736300")
if l:
print(l)
['我', '的', '是', '1', '7', '8', '5', '6', '7', '8', '6', '5', '3', '3', ',', '小', '虎', '的', '是', '1', '8', '8', '9', '2', '7', '3', '6', '3', '0', '0']
regex = re.compile(r"[^电话]*")
l = regex.findall("我的电话是17856786533,小虎的电话是18892736300")
if l:
print(l)
['我的', '', '', '是17856786533,小虎的', '', '', '是18892736300', '']
注意区别
regex = re.compile(r"(电话)+")
l = regex.findall("我的电话是17856786533,小虎的电话是18892736300")
if l:
print(l)
['电话', '电话']
regex = re.compile(r"(电话)*")
l = regex.findall("我的电话是17856786533,小虎的电话是18892736300")
if l:
print(l)
['', '', '电话', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '电话', '', '', '', '', '', '', '', '', '', '', '', '', '']
使用sub()方法替换
Regex.sub(“替换的补料”,“检索的字符串”)
将字符串中满足条件的字串进行替换,返回新的字符串。
regex = re.compile("\d{11}")
str = regex.sub("***","我的电话是17856786533")
print(str)
#我的电话是***
如果替换的补料想使用匹配到的文本本身的一部分,可以在sub()第一个参数中输入\1,\2,\3这里的数字代表匹配模式里的分组中的第几组,从1开始。
不要忘记在第一个参数前面加r,不然会出错。
regex = re.compile(r"(\d{3})\d{4}(\d{4})")
str = regex.sub(r"\1****\2","我的电话是17856786533,你呢?") #加r
print(str)
#我的电话是178****6533,你呢?
使用re.split()分割字符串
相比于使用字符串的spilt()方法切割字符串,re.split()更加的灵活,比如对字符串"hu j, dd, jl"分割,按照逗号分割,不考虑逗号的数量,例如有两个连续的逗号,他们两个之间不应该分开。
str = "hu j,, dd, jl"
lst = str.split(",")
print(lst)
#['hu j', '', ' dd', ' jl'] #列表中有一个空字符串
"""使用re正则表达式切分,更加灵活"""
regex = re.compile(r"[,]+")
lst = re.split(regex,str)
print(lst)
#['hu j', ' dd', ' jl']
复杂的正则表达式
如果正则表达式复杂之后,很容易致使编程人员看不明白,但是由于表达式分布在同一行,所以不能直接加注释。
向re.complie()中传递re.VERBOSE参数,使得其忽略空白符和注释。
re.complie(r"""(
(\d{3}|\(\d{3}\))? #area code
(\s|-\\.)? #separator
\d{3} #first 3 digtis
(\s|-|\.) #separator
\d{4} #last 4 digits
(\s*(ext|x|ext.)\s*\d{2,5})?#extension
)""",re.VERBOSE)
例子
编写一个正则表达式匹配句子,他的第一个单词是Alice、Bob、Cindy第二个单词是eats、pets、throws第三个单词是apples、cats、baseballs
regex = re.compile("(Alice|Bob|Cindy) (eats|pets|throws) (apples|cats|baseballs)")
print(regex.search("Alice eats apples").group())
print(regex.search("Bob pets cats").group())
print(regex.search("Cindy throws baseballs").group())
print(regex.search("Alice throws cats").group())
Alice eats apples
Bob pets cats
Cindy throws baseballs
Alice throws cats
这种用法还挺有意思的