正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成,在爬虫方面更是要和字符串打交道,正则表达式更是不可或缺的技能,正则表达式在不同的语言中使用方式可能不一样,不过只要学会了任意一门语言的正则表达式用法,其他语言中大部分也只是换了个函数的名称而已,本质都是一样的。下面,我们一起来学习下python中的正则表达式是怎么使用的。
一、正则表达简介
1.概念:
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一
种过滤逻辑(可以用来做检索,截取或者替换操作)。正则表述式用于搜索、替换和解析字符串。正则表达式遵循一定的语法规则,使用非常
灵活,功能强大。使用正则表达式编写一些逻辑验证非常方便,例如电子邮件地址格式的验证。
正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符)操作
的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑,正则表达式是一种文
本模式,模式描述在搜索文本时要匹配一个或多个字符串。
2.作用:
给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配")。
可以通过正则表达式,从字符串中获取我们想要的特定部分。
还可以对目标字符串进行替换操作。
二、正则表达式的使用
Python 语言通过标准库中的 re 模块支持正则表达式。re 模块提供了一些根据正则表达式进行查找、替换、分隔字符串的函数,这些函数使用一个正则表达式作为第一个参数。
re模块常用的函数如下表所示。
1.re.match(pattern,string,flags=0)
根据pattern从string的头部开始匹配字符串,只返回第一次匹配成功的对象,否则,返回None
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re
s = 'hello world!'
print(re.match('hello',s).span())
print(re.match('hello',s))
print(re.match('hello',s).group())
m = re.match('Hello',s,re.I)#re.I是 IGNORECASE 忽略大小写
if m is not None:
print('匹配成功结果是:',m.group())
else:
print('匹配失败')
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) #标志位设置为多行匹配,忽略大小写
if matchObj:
print("matchObj.group() : ", matchObj.group())
print("matchObj.group(1) : ", matchObj.group(1))
print("matchObj.group(2) : ", matchObj.group(2))
else:
print("No match!!")
注意:
groups(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
2.re.search(pattern, string, flags=0) search 在一个字符串中搜索满足文本模式的字符串。
pattern匹配的正则表达式,string要匹配的字符串,flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re
s = 'abcdefghabcde'
print(re.search('abc',s))
print(re.search('abc',s).group())
line = "Cats are smarter than dogs"
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print("searchObj.group() : ", searchObj.group())
print("searchObj.group(1) : ", searchObj.group(1))
print("searchObj.group(2) : ", searchObj.group(2))
else:
print("Nothing found!!")
注意:
match和search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
而re.search匹配整个字符串,直到找到一个匹配。
例如:
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print("match --> matchObj.group() : ", matchObj.group())
else:
print("No match")
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print("search --> searchObj.group() : ", matchObj.group())
else:
print("No match")
结果如下:
No match
search --> searchObj.group() : dogs
3.re.compile(pattern[, flags]) 函数用于编译正则表达式,生成一个正则表达式( 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 为了增加可读性,忽略空格和 # 后面的注释
import re
s = 'first123_ line'
regex = re.compile(r'\w+') #匹配至少一个字母数字下划线
m=regex.match(s)
print(m.group())
# s的开头是 "f", 但正则中限制了开始为 i所以匹配失败
regex = re.compile("^i\w+")
print(regex.match(s))
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
m = pattern.match('one12twothree34four')# 查找头部,没有匹配
print(m)#结果为None
m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
print(m)#结果为None
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
print(m)#结果为<_sre.SRE_Match object; span=(3, 5), match='12'>
print(m.group(),m.start(),m.end(),m.span())
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写
m = pattern.match('Hello World Wide Web')
print(m)# 匹配成功,返回一个 Match 对象<_sre.SRE_Match object; span=(0, 11), match='Hello World'>
print(m.group(0))# 返回匹配成功的整个子串
print(m.group(1))# 返回第一个分组匹配成功的子串
print(m.group(2))# 返回第二个分组匹配成功的子串
print(m.groups())# 等价于 (m.group(1), m.group(2), ...)
print(m.span(0))# 返回匹配成功的整个子串的索引
print(m.span(1))# 返回第一个分组匹配成功的子串的索引
print(m.span(2))# 返回第二个分组匹配成功的子串
print(m.group(3))# 不存在第三个分组
注意:
当匹配成功时返回一个 Match 对象,其中:
group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
span([group]) 方法返回 (start(group), end(group))。
4.re.findall(string[, pos[, endpos]])
根据pattern在string中匹配字符串,如果匹配成功返回包含匹配结果的列表,否则返回空列表。
string 待匹配的字符串;pos 可选参数,指定字符串的起始位置,默认为 0;endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('runoob 123 google 456')
print(result1)
result2 = pattern.findall('run88oob123google456', 0, 10)
print(result2)
result3 = re.findall(r'\w+','first 1 second 2 third 3')
print(result3)
result4 = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
print(result4)
注意: match 和 search 是匹配一次 findall 匹配所有。
5.re.finditer(pattern, string, flags=0)
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
pattern匹配的正则表达式;string要匹配的字符串;flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re
it = re.finditer(r"\d+","12a32bc43jf3")
for match in it:
print(match.group())
it = re.finditer(r'\w+','first 1 second 2 third 3')
for match in it:
print(match.group())
6.re.sub(pattern,repl,string,count=0) 根据指定的正则表达式,替换源字符串中的子串。
pattern 是一个正则表达式,repl 是用于替换的字符串,string 是源字符串。如果 count 等于 0,则返回 string 中匹配的所有结果;如果 count 大于 0,则返回前 count 个匹配
import re
phone = "2004-959-559 # 这是一个国外电话号码"
# 删除字符串中的 Python 注释
num = re.sub(r'#.*$', "", phone)
print("电话号码是: ", num)
# 删除非数字(-)的字符串
num = re.sub(r'\D', "", phone)
print("电话号码是 : ", num)
#subn 函数的使用
result=re.subn(r'\D', "", phone)
print(result)
print('替换的结果:',result[0])
print('替换的次数:',result[1])
结论:
sub函数和 subn函数用于实现搜索和替换功能。
这两个函数的功能几乎完全相同,都是将某个字符串中所有匹配正则表达式的部分替换成其他字符串。
用来替换的部分可能是一个字符串,也可以是一个函数,该函数返回一个用来替换的字符串。
sub函数返回替换后的结果,subn函数返回一个元组,元组的第 1个元素是替换后的结果,第 2个元素是替换的总数。
7.re.split(pattern, string[, maxsplit=0, flags=0])
split函数用于根据正则表达式分隔字符串,也就是说,将字符串与模式匹配的子字符串都作为分隔符来分隔这个字符串。split 函数返回一个列表形式的分隔结果,
每一个列表元素都是分隔的子字符串。
pattern 匹配的正则表达式;string 要匹配的字符串;maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数;
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
import re
s = 'first 11 second 22 third 33'
#按数字切分
print(re.split(r'\d+',s))
# maxsplit 参数限定分隔的次数,这里限定为 1,也就是只分隔一次
print(re.split(r'\d+',s,1))
三、正则表达式对象
re.RegexObject
re.compile() 返回 RegexObject 对象。
re.MatchObject
group() 返回被 RE 匹配的字符串。
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置
四、正则表达式修饰符
1.可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。
多个标志可以通过按位 OR(|) 它们来指定。
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
2.正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 '\\t')匹配相应的特殊字符。
下面列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
边界匹配(不消耗带匹配字符串中的字符)
--------------------------------------------------------
^ 匹配字符串的开头,在多行模式中匹配每一行的开头
$ 匹配字符串的末尾,在多行模式中匹配每一行的末尾
\A 仅匹配字符串开始
\Z 仅匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\b 匹配一个单词边界即匹配\w和\W之间,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界[^\b]。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
--------------------------------------------------------
一般字符
--------------------------------------------------------
. 匹配任意字符,除了\n,当re.DOTALL标记被指定时,则可以匹配包\n的任意字符。
\ 转义字符,使后一个字符改变原来的意思。如果字符串中有字符*需要匹配,可以使用\*或者字符集[*]
[...] 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
[^...] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
--------------------------------------------------------
数量词(用在字符或者(...)之后)
--------------------------------------------------------
* 匹配前一个字符0次或无限次
+ 匹配前一个字符1次或无限次
? 匹配前一个字符0次或1次,非贪婪方式
{n} 匹配前一个字符n次。例如, o{2}不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的两个 o。
{n,} 匹配 前一个字符n次到无限次。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。"o{1,}" 等价于 "o+"。"o{0,}" 则等价于 "o*"。
{n, m} 匹配前一个字符 n到 m次,贪婪方式
--------------------------------------------------------
逻辑、分组
--------------------------------------------------------
| |代表左右表达式任意匹配一个,先尝试匹配左边表达式,一旦成功则跳过匹配右边表达式,如果|没有被包括在()中,则表示它的范围是整个正则表达式
(...) 被括起来的表达式将作为分组,从表达式左边开始每遇到一个分组的左括号,编号+1,另外,分组表达式作为一个整体可以后接数量词,表达式中的|仅在该组中有效
(?P<name>...) 分组,除了原有的编号外再指定一个额外的别名
\<number> 引用编号为<number>的分组匹配到字符串
(?P=name) 应用别名为<name>的分组匹配到字符串
--------------------------------------------------------
特殊构造(不作为分组)
--------------------------------------------------------
(?:...) (...)的不分组版本,用于使用|或后接数量词
(?!iLmsux) iLmsux的每个字符代表一个匹配模式,只能用在正则表达式的开头,可选多个
(?#...) #后的内容将作为注释被忽略
(?=...) 之后的字符串内容需要匹配表达式才能成功匹配。不消耗字符串内容
(?!...) 之后的字符串内容需要不匹配表达式才能成功匹配。不消耗字符串内容
(?>...) 匹配的独立模式,省去回溯。
(?<=...) 之前的字符串内容需要匹配表达式才能成功匹配。不消耗字符串内容
(?<!...) 之前的字符串内容需要不匹配表达式才能成功匹配。不消耗字符串内容
(?(id/name)yes-pattern|no-pattern) 如果编号为id/别名为name的组匹配到字符,则需要匹配yes-pattern,否则需要匹配no-pattern,|no-pattern可以忽略。
--------------------------------------------------------
预定义字符集(可以写在字符集[...]中)
--------------------------------------------------------
\w 匹配字母数字及下划线[A-Za-z0-9_]
\W 匹配非字母数字及下划线,等价于[^\w]
\s 匹配任意空白字符,等价于 [ \t\n\r\f\v]。
\S 匹配任意非空字符等价于[^\s]
\d 匹配任意数字:[0-9]
\D 匹配任意非数字,等价于[^\d]
--------------------------------------------------------
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1...\9 匹配第n个分组的内容。
\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。
(?imx) 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx) 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?imx:...) 在括号中使用i, m, 或 x 可选标志
(?-imx:...) 在括号中不使用i, m, 或 x 可选标志
--------------------------------------------------------
五、贪婪模式和费贪婪模式
贪婪模式指 Python 里数量词默认是贪婪的,总是尝试匹配尽可能多的字符。非贪婪模
式与贪婪相反,总是尝试匹配尽可能少的字符,可以使用"*","?","+","{m,n}"后面加上?,使
贪婪变成非贪婪
import re
#贪婪模式下.+中的.会尽可能多的匹配
v = re.match(r'(.+)(\d+-\d+-\d+)','This is my tel:133-1234-1234')
print('----------贪婪模式---------')
print(v.group(1))
print(v.group(2))
print('----------非贪婪模式---------')
v = re.match(r'(.+?)(\d+-\d+-\d+)','This is my tel:133-1234-1234')
print(v.group(1))
print(v.group(2))
print('贪婪模式')
v= re.match(r'abc(\d+)','abc123')
print(v.group(1))
print('非贪婪模式')
v= re.match(r'abc(\d+?)','abc123')
print(v.group(1))
python基础语法13-正则表达式
最新推荐文章于 2024-03-15 07:46:31 发布