一、正则表达式介绍
正则表达式是一种用于匹配、查找、替换文本的强大工具。它通过特定的语法规则,定义字符串的模式,用来匹配指定规则的字符串,从而快速处理复杂的文本操作。正则表达式包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),可以用来描述和匹配字符串的特定模式。
1.1、正则表达式的模式
正则表达式的模式可以包括以下几类:
字面值字符:
按照字面意义进行匹配如字母、数字、空格等,例如匹配字母 "a" 将匹配到文本中的 "a" 字符。
元字符:元字符具有特殊的含义
\d # 匹配数字字符,等价于 [0-9]
\D # 匹配非数字字符,等价于 [^0-9]
\w # 匹配单词字符(字母、数字、下划线),等价于 [a-zA-Z0-9_]
\W # 匹配非单词字符 ,等价于 [^a-zA-Z0-9_]
\s # 匹配空白字符(包括空格、换行符、制表符)
\S # 匹配非空白字符
. # 匹配任意字符(换行符除外) 示例:a.b 匹配 "aab", "a1b", "a b" 等
边界匹配
^ # 匹配字符串的开头 示例:^abc 匹配以 "abc" 开头的字符串
$ # 匹配字符串的结尾 示例:xyz$ 匹配以 "xyz" 结尾的字符串
\b # 匹配单词边界 示例:\bcat\b 匹配 "cat" 但不匹配 "category"
\B # 匹配非单词边界 示例:\Bcat\B 匹配 "scattered" 中的 "cat" 但不匹配单独的 "cat"
字符类
[] # 匹配括号内的任意一个字符 示例:[aeiou] 匹配任意一个元音字母
[^] # 匹配除了括号内的字符以外的任意一个字符 示例:[^0-9] 匹配任意非数字字符
- # 在字符类中表示范围 示例:[a-z] 匹配任意小写字母
量词
* # 匹配前面的模式零次或多次 示例:ab*c 匹配 "ac", "abc", "abbc" 等
+ # 匹配前面的模式一次或多次 示例:ab+c 匹配 "abc", "abbc" 但不匹配 "ac"
? # 匹配前面的模式零次或一次 示例:colou?r 匹配 "color" 和 "colour"
{n} # 匹配前面的模式恰好 n 次 示例:a{3} 匹配 "aaa"
{n,} # 匹配前面的模式至少 n 次 示例:a{2,} 匹配 "aa", "aaa" 等
{n,m} # 匹配前面的模式至少 n 次且不超过 m 次 示例:a{2,4} 匹配 "aa", "aaa", "aaaa"
分组和捕获
() # 用于分组和捕获子表达式 示例:(ab)+ 匹配 "ab", "abab" 等 额外捕获最后一个 "ab" 到分组 $1
(?:) # 用于分组但不捕获子表达式 示例:(ab)+ 匹配 "ab", "abab" 等 不捕获分组
特殊字符
\ # 转义字符,用于匹配特殊字符本身 示例:\. 匹配实际的点号而不是任意字符
. # 匹配任意字符(除了换行符) 示例:a.b 匹配 "aab", "a1b", "a b" 等
| # 用于指定多个模式的选择 示例:cat|dog 匹配 "cat" 或 "dog"
修饰符
i # 忽略大小写 示例:/abc/i 可以匹配 "abc", "Abc", "ABC" 等
g # 全局匹配忽略大小写 示例:在字符串 "ababab" 中,/ab/g 会匹配所有三个 "ab"
m # 多行模式 示例:在多行字符串中,/^abc/m 会匹配每行开头的 "abc"
除了这里介绍的常用的模式外,正则表达式还有一些不常用的模式这里就不再进行介绍,以上已经基本包含日常用到的全部了。
1.2、贪婪匹配与惰性匹配
默认情况下,量词(*, +, ?, {})是贪婪的,会尽可能多地匹配字符。在量词后加?可使其变为非贪婪(懒惰)模式:
*? # 零次或多次,但尽可能少
+? # 一次或多次,但尽可能少
?? # 零次或一次,但尽可能少
{n,m} # n到m次,但尽可能少
示例:<div>hello world</div> <.*?> 匹配HTML标签时不会跨标签匹配,只匹配<div>。但是<.*>会匹配<div>hello world</div>
1.3、运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:
\ 转义符
(), (?:), (?=), [] 圆括号和方括号
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \任何元字符、任何字符 定位点和序列(即:位置和顺序)
| 替换,"或"操作
如上所示,\的优先级是最高的。
二、re模块
python提供了re模块用来进行正则匹配。这里逐个介绍一下常用的功能:
2.1、re.findall()函数
findall获取所有匹配到的所有值,返回一个列表。
>>> import re
>>> print(re.findall('.+', 'abd\ndef\ng')) # .匹配任意字符,换行符除外
['abd', 'def', 'g']
>>> print(re.findall('.+', 'abd\ndef\ng', flags=re.DOTALL)) # 加上flags=re.DOTALL后 .就可以匹配所有字符包括换行符
['abd\ndef\ng']
这里重点需要注意下flag参数,re模块还有其他的flag选项,例如 re.M 启用多行模式。 re.S是re.DOTALL的简写,使.可以匹配换行符。re.I忽略大小写。
2.2、re.search()函数
search的用法和findall一模一样,区别是返回值。search只会返回匹配规则的第一个值,返回一个Match对象。
>>> res = re.search('\d{3,4}-\d{7,8}', 'Tel:028-7654321')
>>> print(res)
<re.Match object; span=(4, 15), match='028-7654321'>
>>> print(res.span())
(4, 15)
>>> print(res.group())
028-7654321
如上所示,search函数返回一个macth对象,span()是匹配到的索引位置,通过group()就可以获取到匹配的内容。
2.3、分组与捕获
>>> re.findall('(ab)+', 'ababcdaab')
['ab', 'ab']
>>> re.findall('(?:ab)+', 'ababcdaab')
['abab', 'ab']
>>> res = re.search('(ab)+', 'ababcdaab')
>>> res.group()
'abab'
>>> res.group(1)
'ab'
在python中,正则表达式被小括号括起来的部分认为是一个分组。使用(?:)就可以不进行组的捕获。这里说一下组的捕获过程,(ab)+ 完整匹配是匹配到abab,因为ab被连续匹配了两次,但是捕获组只捕获到最后一次匹配,因此findall和group(1)只返回一个ab。group(0)返回整个正则的匹配结果。
2.4、re.finditer()函数
finditer()函数的功能是匹配所有符合规则的内容,返回一个迭代器, 并且通过迭代器拿到的也是Match对象。
res = re.finditer('(\d{3,4})-(\d{7,8})', 'Tel:028-7654321 Tel:029-97654321')
for m in res:
print(m.group())
2.4、re.compile()函数
compile()可以传一个正则表达式,返回的是一个正则表达式对象。
res = re.compile('.*') # 返回一个正则表达式对象。
compile多用于用于一个正则表达式被多次匹配的情况,用正则表达式对象再调用findall,search等函数就不需要再传正则字符串了。
2.5、其他函数
- re.match它只匹配符合规则的第一个值,但是它只能匹配字符串的开头且只能匹配第一行
- re.fullmatch是匹配字符串整体。
- re.sub是将匹配到的内容替换成其他内容。
- re.split是把匹配到的内容作为分隔符进行拆分。
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付
