正则表达式1:基本知识

一、正则匹配的基本知识
1.1 正则表达式的基本概念
正则表达式是对字符串进行操作的一种逻辑公式,就是用事先设定好的一些特定字符,及这些字符的组合组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑
正则表达式是用来匹配字符串的一种强大工具。
1.2 正则表达式的基本概念

语法说明表达式实例完整匹配的字符串
一般字符匹配本身abcabc
.匹配除换行符以外的所有字符a.cabc
\转译字符,使用后改变字符原本的意思a\.ca.c
a\\ca\c
[…]字符集,对应的位置可以是字符集中的任意字符,字符集中的字符可以逐个列出,也可以给出范围,如[abc]或者[a-c],第一个字符^代表取反,如[^abc]代表不是abc的其他字符a[bcd]eabe ace ade
所有的特殊字符在字符集中都失去其原有的意义,在字符集中如果要使用]、-或^,可以在前面加上反斜杠,或者把]、-放在第一个字符,把^放在非第一个字符。
\d数字:[0-9]a\dca1c
\D非数字:[^\d]a\Dcabc
\s空白字符:[空格 \t \r \n \f \v]a\sca c
\S非空白字符:[^\s]a\Scabc
\S非空白字符:[^\s]a\Scabc
\w单词字符:[A-Z a-z 0-9 ]a\w cabc
\W非单词字符:[^\w ]a\W ca c
数量词(用在字符或(…)之后)
*匹配前一个单词0次或者无限次abc*ab abccc
+匹配前一个单词1次或者无限次abc+abc abccc
匹配前一个单词1次或者0次abc?ab abc
{m}匹配前一个字符m次ab(2)cabbc
{m,n}匹配前一个字符m至n次,m和n可以省略:若省略m,则匹配0-n次;若省略n,则匹配m至无限次ab(1,2)cabc abbc
*? +? ??使* + ?(m,n)变成非贪婪模式示例将在下文中讲解
边界匹配(不消耗匹配字符串中的字符)
^匹配字符串中的开头,多行匹配中匹配每一行的开头^abcabc
$匹配字符串中的结尾,多行匹配中匹配每一行的结尾abc$abc
\A仅匹配字符串中的开头\Aabcabc
\Z仅匹配字符串中的结尾abc\Zabc
[\u4e00-\u9fa5]+匹配所有的汉字
逻辑、分组
||代表匹配表达式中任意一个, 但会优先尝试左边的表达式,一旦匹配成功就跳过右边的表达式abc|defabc def
(…)()代表一个分组,分组做为一个整体进行处理,分组中也可以接量词或者|,但是|仅在该组中有效a(123|456)ca123c a456c

二、re及相关模块的使用
2.1、re.compile 函数
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:

pattern : 一个字符串形式的正则表达式
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式
re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X 为了增加可读性,忽略空格和 # 后面的注释
flags代表匹配的方式

例1:

import re
pattern = re.compile(r'\d+')                    # 用于匹配其中的任意数字
m = pattern.findall('one12twothree34four') 
m

[‘12’, ‘34’]

import re
pattern = re.compile(r'"the"')                    # 用于匹配至少一个数字
m = pattern.findall('The fat cat sat on the mat') 
print(m)

输出为[ ]
因为正则表达式大小写敏感
正则表达式是大小写敏感的,所以The不会匹配the。
2.2 正则表达式相关搜索函数
①match
从字符串开头开始匹配,匹配成功就返回一个对象,失败就返回None
语法:match(pattern,string)

import re
print(re.match("hello",'hello pc').group())
结果:
hello

②search
函数在字符串中查找模式匹配,只要找到第一个匹配就返回,没有就返回None
语法:search(pattern,string)
例1:

res=re.compile('[a-zA-Z]{3}')
str1='123abc456'
print(re.search(res,str1).group())
结果:
abc

注意:两者区别:match的匹配是从字符串的开头开始匹配,即如果字符串开头不符合正则表达式规律就返回None,search是搜索整个字符串,如果整个字符串中没有符合正则表达规律的就返回None,如果有立刻返回,search只匹配一次,即使字符串中有多个符合标准的字符串也只返回一个(这里要和find区别,find是返回字符串中的符合标准的字符串位置。)
例如:str1=‘123abc456’,str1.find(‘abc’),返回3)。
例如:re.match(“1000”,“lalal1000”)就返回None。
③ findall
匹配符合正则表达式的所有字符
语法:findall(pattern, string ,flags=0)

str1="彭闯"
a=re.findall("pengchuang",str1)
print(a)
#结果:[]

str1='java=1000,python=9090'  
info=re.findall(r'\d+',str1)#'\d'代表任意一个数字,'+'可以匹配数字一次或者无限次,只能匹配最前
print(info)
#结果:['1000', '9090']

str1="1 0 0 0 "
info=re.findall(r'\d+',str1)#'\d'代表任意一个数字,'+'可以匹配数字一次或者无限次,只能匹配最前
print(info)
#结果:['1','0','0','0']

pattern=re.compile('[a-zA-Z]+')    #匹配任意长度的英文字符
pattern=re.compile('[a-z][a-zA-Z][a-zA-Z]')    #匹配3个长度的英文字符 
str1='123abc456def789'
result=re.findall(pattern,str1)
print(result)
#结果:['abc', 'def']

pattern=re.compile('a(123|456)c')    #匹配3个长度的英文字符 
str1='a123ca456c'
result=re.findall(pattern,str1)
print(result)
#结果:['123', '456']
#findall遇见分组会优先返回分组的内容

findall会匹配所有找到的字符,如果找到了会将所有字符返回列表,如果没找到,则会返回[ ]
总结:findall会匹配所有字符,如果找到了会将所有字符返回列表,如果没找到,则会返回[ ]
④ finditer()
finditer(pattern,str):finditer会顺序访问每一个匹配结果。不管正则表达式中是否含有分组。

pattern=re.compile('a(123|456)c')    #匹配3个长度的英文字符 
str1='a123ca456c'
result=re.finditer(pattern,str1)
for i in result:
    print(i.group())
a123c
a456c
for i in result:
    print(i.group(1))  #返回每个分组的第二词
1
4

⑤split()
split(patten,string):按照正则匹配的字串将字符串进行分割

str1='我叫pc,大家好'
str1.split(",")

print(re.split('\d+','one1two2three3four4five5'))
print(re.split('\W+','one,two,three,four,five'))
['one', 'two', 'three', 'four', 'five', '']
['one', 'two', 'three', 'four', 'five']

⑥sub(),使用re替换string中每一个匹配的字串后返回替换后的字符串
语法sub(pattern,‘替换符号’,string)

print(re.sub('\d+','-','one1two2three3four4five5'))
#结果:
one-two-three-four-five-

⑦subn(),返回替换次数

print(re.subn('\d+','-','one1two2three3four4five5'))
('one-two-three-four-five-', 5)

⑧引用分组

strs='hello 123,world 321'
pattern=re.compile('(\w+) (\d+)')
for i in pattern.finditer(strs):
    print(i)
    print(i.group(0))
    print(i.group(1))
    print(i.group(2))
结果:
hello 123
hello
123
world 321
world
321
这是因为分组以后,group(0)为整个分组的字符串,group(1)为当前分组的第一个字符串。group(2)为当前分组的第二个字符串。

strs='hello 123,world 321'
pattern=re.compile('(\w+) (\d+)')
print(pattern.sub(r'\2 \1',strs))  #颠倒分组
print(pattern.sub(r'\2+++\1',strs))  #颠倒分组
结果:
123 hello,321 world
123+++hello,321+++world

⑨贪婪匹配和非贪婪匹配
贪婪:在整个表达式匹配成功的前提下,尽可能多的匹配
非贪婪:在整个表达式匹配成功的前提下,尽可能少的匹配
例1:

1、
str1='aaa<p>hello<\p>bbb<p>world<\p>ccc'
pattern=re.compile(r'<p>\w+<\\p>') #匹配两个p之间的字符1个或者无限个
print(pattern.findall(str1))
2、
str1='aaa<p>hello<\p>bbb<p>world<\p>ccc'
pattern=re.compile(r'<p>.*<\\p>') #匹配两个p之间的字符1个或者无限个
print(pattern.findall(str1))
结果:
['<p>hello<\\p>', '<p>world<\\p>']
['<p>hello<\\p>bbb<p>world<\\p>']

2、 元字符
正则表达式主要依赖于元字符。 元字符不代表他们本身的字面意思,他们都有特殊的含义。一些元字符写在方括号中的时候有一些特殊的意思。以下是一些元字符的介绍:

元字符	描述
.	句号匹配任意单个字符除了换行符。
[ ]	字符种类。匹配方括号内的任意字符。
[^ ]	否定的字符种类。匹配除了方括号里的任意字符
*	匹配>=0个重复的在*号之前的字符。
+	匹配>=1个重复的+号前的字符。
?	标记?之前的字符为可选.
{n,m}	匹配num个大括号之前的字符 (n <= num <= m).
(xyz)	字符集,匹配与 xyz 完全相等的字符串.
|	或运算符,匹配符号前或后的字符.
\	转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |
^	从开始行开始匹配.
$	从末端开始匹配.

2.1 点运算符 .
.是元字符中最简单的例子。 .匹配任意单个字符,但不匹配换行符。 例如,表达式.ar匹配一个任意字符后面跟着是a和r的字符串。

import re
pattern = re.compile(r'.ar')             #匹配以ar结尾的单词
m = pattern.findall('The car parked in the garage.') 
print(m)

[‘car’, ‘par’, ‘gar’]
2.2 字符集[ ]
字符集也叫做字符类。 方括号用来指定一个字符集。 在方括号中使用连字符来指定字符集的范围。 在方括号中的字符集不关心顺序。 例如,表达式[Tt]he 匹配 the 和 The。
例1:

import re
pattern = re.compile(r'[T|t]he')                    # 匹配以The和the的单词
m = pattern.findall('The car parked in the garage.') 
print(m)

[‘The’, ‘the’]

例2:
方括号的句号就表示句号。 表达式 ar[.] 匹配 ar.字符串

"ar[.]" => A garage is a good place to park a car.

匹配 ar.
2.2.1 否定字符集
例3:

一般来说 ^ 表示一个字符串的开头,但它用在一个方括号的开头的时候,它表示这个字符集是否定的。 
例如,表达式[^c]ar 匹配一个后面跟着ar的除了c的任意字符。
#匹配不以c开头但是以ar结尾的单词
"[^c]ar" => The car parked in the garage.

2.3 重复次数

后面跟着元字符 +,* or ? 的,用来指定匹配子模式的次数。 这些元字符在不同的情况下有着不同的意思。
2.3.1 * 号

*号匹配 在*之前的字符出现大于等于0次。 
例如,表达式 a* 匹配0或更多个以a开头的字符。表达式[a-z]* 匹配一个行中所有包含小写字母的字符串。
"[a-z]*" => The car parked in the garage

结果
[‘he car parked in the garage’]
例2:

*字符和.字符搭配可以匹配所有的字符.**和表示匹配空格的符号\s连起来用,如表达式\s*cat\s*匹配0或更多个空格开头和0或更多个空格结尾的cat字符串。
"\s*cat\s*" => The fat cat sat on the concatenation.
pattern = re.compile(r'\s*cat\s*')                    # 匹配以The和the的单词
m = pattern.findall('The fat cat sat on the concatenation') 
print(m)
[' cat ', 'cat']

例3:匹配单词中包含cat的字符串

4:
pattern = re.compile(r'\w*cat\w*')                    # 匹配包含cat这个单词的字符
m = pattern.findall('The fat cat sat on the concatenation') 
print(m)

[‘cat’, ‘concatenation’]

2.3.2 + 号

+号匹配+号之前的字符出现 >=1 次。 例如表达式c.+t 匹配以首字母c开头以t结尾,中间跟着至少一个字符的字符串。
"c.+t" => The fat cat sat on the mat.

匹配到的字符串
[‘cat sat on the mat’]
注意这里我们一定是贪心匹配,即匹配最多的字符串
2.3.3 、? 号

在正则表达式中元字符 ? 标记在符号前面的字符为可选,即出现 01 次。 例如,表达式 [T]?he 匹配字符串 he 和 The。

"[T]he" => The car is parked in the garage.

结果:
[‘The’]
2.4、 {} 号
在正则表达式中 {} 是一个量词,常用来一个或一组字符可以重复出现的次数。 例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字。
例1:

"[0-9]{2,3}" => The number was 9.9997 but we rounded it off to 10.0.
pattern = re.compile(r'[0-9]{2,3}')                    
m = pattern.findall('The number was 9.9997 but we rounded it off to 10.0.') 
print(m)

结果:
[‘999’, ‘10’]
例2:

'''
匹配11位手机号码
'''
pattern = re.compile(r'[0-9]{11}')
m = pattern.findall('我今年11岁,我的手机号码是17798558749') 
print(m)

[‘17798558749’]
例3:
我们可以省略第二个参数。 例如,[0-9]{2,} 匹配至少两位 0~9 的数字。

"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.

结果:
[‘999’, ‘10’]
2.5、 […] 特征标群
特征标群是一组写在 […]中的子模式。表示取出方括号中的字符

1[c|g|p]ar 匹配 car 或 gar 或 par.
"[c|g|p]ar" => The car is parked in the garage.
['car','par','gar']

2.6 | 或运算符
或运算符就表示或,用作判断条件。

1(T|t)he|car 匹配 (T|t)he 或 car。
"(T|t)he|car" => The car is parked in the garage.

2.7 转码特殊字符
反斜线 \ 在表达式中用于转码紧跟其后的字符。用于指定 { } [ ] / \ + * . $ ^ | ? 这些特殊字符。如果想要匹配这些特殊字符则要在其前面加上反斜线 \。

1 匹配句子中所有以'fat','cat','mat',或者+'.'结尾的符号
"[f|c|m]at\.?" => The fat cat sat on the mat.
pattern = re.compile("[f|c|m]at\.?") 
m = pattern.findall('The fat cat sat on the mat.')
print(m)

[‘fat’, ‘cat’, ‘mat.’]
如果我不加.?则最后一个只会出现cat
例2

匹配以fat,cat,mat+.结尾的字符
pattern = re.compile("[f|c|m]at\.") 
m = pattern.findall('The fat cat sat on the mat.')
print(m)

[‘mat.’]
例3:

匹配以fat,cat,mat+.结尾的字符
pattern = re.compile("[f|c|m]at\.") 
m = pattern.findall('The fat cat sat on the mat.')
print(m)

例4:

2.8 锚点
在正则表达式中,想要匹配指定开头或结尾的字符串就要使用到锚点。^ 指定开头,$ 指定结尾。
2.8.1 ^ 号
^ 用来检查匹配的字符串是否在所匹配字符串的开头。
例如,在 abc 中使用表达式 ^a 会得到结果 a。但如果使用 ^b 将匹配不到任何结果。因为在字符串 abc 中并不是以 b 开头。
例1:

匹配以 The 或 the 开头的字符串。
pattern = re.compile('^[T|t]he') 
m = pattern.findall('The car is parked in the garage.')
print(m)

[‘The’]
因为正则匹配时将后面的字符串看做一整个字符串,所以美亚匹配到the
2.8.2 $ 号
同理于 ^ 号,$ 号用来匹配字符是否是最后一个。

'''
例10
匹配以 at.结尾的字符串。
'''
pattern = re.compile('at\.') 
m = pattern.findall('The fat cat. sat. on the mat.')
print(m)
['at.', 'at.', 'at.']
pattern = re.compile('at\.$') 
m = pattern.findall('The fat cat. sat. on the mat.')
print(m)
['at.']

可以看出加上$代表以at.结尾且是最后一个字符的字符串
3. 简写字符集
正则表达式提供一些常用的字符集简写。如下:

简写 描述

.	除换行符外的所有字符
\w	匹配所有字母数字,等同于 [a-zA-Z0-9_]
\W	匹配所有非字母数字,即符号,等同于: [^\w]
\d	匹配数字: [0-9]
\D	匹配非数字: [^\d]
\s	匹配所有空格字符,等同于: [\t\n\f\r\p{Z}]
\S	匹配所有非空格字符: [^\s]
\f	匹配一个换页符
\n	匹配一个换行符
\r	匹配一个回车符
\t	匹配一个制表符
\v	匹配一个垂直制表符
\p	匹配 CR/LF(等同于 \r\n),用来匹配 DOS 行终止符
\b:表示字母数字与非字母数字的边界
\B:非字母数字与非字母数字的边界。
补充:
[\u4e00-\u9fa5]+ 匹配所有的汉字

4、 前后预查
零宽度断言如下:

符号	描述
?=	正先行断言-存在
?!	负先行断言-排除
?<=	正后发断言-存在
?<!	负后发断言-排除

4.1、 ?=… 正先行断言
1、 什么是零宽断言
  有时候在使用正则表达式做匹配的时候,我们希望匹配一个字符串,这个字符串的前面或后面需要是特定的内容,但我们又不想要前面或后面的这个特定的内容,这时候就需要零宽断言的帮助了。所谓零宽断言,简单来说就是匹配一个位置,这个位置满足某个正则,但是不纳入匹配结果的,所以叫“零宽”,而且这个位置的前面或后面需要满足某种正则。
2、四种正则表达
(1)正预测先行:简称正向先行断言,语法:(?=exp),它断言此位置的后面能匹配表达式exp,但不包含此位置;如:a(?=\d),返回匹配字符串中以数字为结尾的a字符。
(2)正回顾后发:简称正向后发断言,语法:(?<=exp),它断言此位置的前面能匹配表达式exp;
如:(?<=\d)a,返回匹配字符串中以数字为开头的a字符。
(3)负预测先行:简称反向先行断言,语法:(?!exp),它断言此位置的后面不能匹配表达式exp;
如:a(?!\d),返回不匹配字符串中以数字结尾的a字符。
(4)负回顾后发:简称反向后发断言,语法:(?<!exp),它断言此位置的前面不能匹配表达式exp;
如:a(?<!exp)a,返回不匹配字符串中以数字开头的a字符。

4.1、正向先行(?=exp):获取字符串中以ing结尾的字符:
在这里插入图片描述
4.2
正向后发(?<=exp):获取字符串中以do开头的单词后半部分:

s='doing done do todo'
pattern = re.compile(r'(?<=\bdo)\w+\b') 
m = pattern.findall(s)
print(m)

[‘ing’, ‘ne’]
4.3、反向先行(?!exp):匹配出字符串中不是以ing结尾的单词:

s='do run going'
pattern = re.compile(r'\b\w+\W(?!ing)') 
m = pattern.findall(s)
print(m)

['do ', 'run ']
4.4、反向后发(?<!exp):匹配字符串中不以do开头的单词:
在这里插入图片描述
5. 标志
5.1 惰性匹配
python的正则表达一般都是贪心算法,即匹配出符合要求的最大字符串

s='The fat cat sat on the mat.'
pattern = re.compile(r'.*at') 
m = pattern.findall(s)
print(m)

[‘The fat cat sat on the mat’]
如果我们要非惰性匹配,则需要

s='The fat cat sat on the mat.'
pattern = re.compile('.*?at') 
m = pattern.findall(s)
print(m)

[‘The fat’, ’ cat’, ’ sat’, ’ on the mat’]
我们发现对于fat这个词来说,满足以at结尾,且前面有字符,
cat同样满足,且The fat cat也满足,我们选择一个最小的。
sat也满足,且sat在满足的情况下最小
mat也满足,且满足的情况下最小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值