正则表达式也叫做REs, regex, 或者regex patterns. 通常正则表达式中出现的任意一个字符代表匹配和他们一样的字符, 但正则表达式也提供了额外的符号来表达更加复杂的含义.
基本符号
以下符号相当于各种编程语言的关键字, 它们并不匹配他们本身
1 | . ^ $ * + ? { } [ ] \ | ( ) |
上述转义字符前加上\可以去除之后的一个字符的转义, 例如 \]
匹配字符 ]
字符类
- 在 “[“ 和 “]” 中的若干字符构成一个字符类(character class)
- 一个字符类表示, 此位置可以匹配这个类中的任意一个字符
- 可以使用-来表示一个范围, 例如[a-c]表示[abc]
- 在字符类中的特殊符号不被转义
反向匹配
- 在字符类中, 如果以^开头, 则表示匹配除此字符类中提及的任何其他字符
- 例如[^5]匹配任何不是5的字符
转义字符
字符 | 解释 | 等价正则表达式 |
---|---|---|
\d | 匹配任意数字 | [0-9] |
\D | 匹配任意的非数字 | [^0-9] |
\s | 匹配任意空白字符 | [ \t\n\r\f\v] (第一个是空格) |
\S | 匹配任意非空白字符 | [^ \t\n\r\f\v] |
\w | 匹配任意字符数字(alphanumeric) | [a-zA-Z0-9_] (最后一个是下划线) |
\W | 匹配任意非字符数字 | [^a-zA-Z0-9_] |
说明:这些字符可以和其他字符一样出现在任何合法的地方
高级的转义字符
符号 | 效果 |
---|---|
| | 相当于或, A|B表示此处可以匹配A或者B |
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
\A | 强制匹配字符串开头, 无视MULTILINE标记 |
\Z | 强制匹配字符串结尾, 无视MULTILINE标记 |
\b | 匹配单词边界, 即非字母数字的任意其他字符 |
\B | 匹配非单词边界字符, \b的反义 |
使用重复功能
符号 | 效果 |
---|---|
* |
使此符号之前的字符重复0到多次 |
+ |
使此符号之前的字符重复1到多次 |
? | 使此符号之前的字符重复0到1次 |
{m,n} | 使此符号之前的字符重复至少m次, 至多n次(含n) |
说明:这些字符都是采用贪婪匹配, 即尽可能多的重复, 从而匹配到最长的符合要求的字符串,如果想要最短匹配们可以在相应的符号后加上一个?
,例如*?
, +?
等
Python和正则表达式
1 | import re |
在Python中使用正则表达式需要两步, 即
- 导入re库
- 编译正则表达式
使用原生字符串
在正则表达式中, 使用\
表示转义, 而在Python中碰巧也使用同样的符号表示转义,因此在正则表达式中, 如果需要使用\
, 在Python的字符串中, 就要输入两个\
, 即\\
为了避免输入太多\导致正则表达式难以理解, 可以使用Python的原生字符串, 即在字符串开头加上r
,例如r"\sda"
,在这个字符串中, 所有字符都是原来的字符, Python不进行任何转义
Re库主要函数功能
函数 | 说明 |
---|---|
re.compile() | 将一个字符串编译成正则表达式 |
re.search() | 在一个字符串中搜索匹配的正则表达式的第一个位置, 返回match对象 |
re.match() | 在一个字符串中强制从开始位置起匹配正则表达式, 返回match对象 |
re.findall() | 搜索字符串, 以列表类型返回全部能匹配的子串 |
re.split() | 将一个字符串按照正则表达式匹配结果进行分割, 返回列表类型 |
re.finditer() | 搜索字符串中全部匹配结果, 返回一个迭代类型, 每个迭代元素是match对象 |
re.sub() | 在一个字符串中替换所有匹配正则表达式的子串, 返回替换后的字符串 |
- regex = re.compile(pattern,flags=0)
- pattern:正则表达式的字符串或者原生字符串
- flags:正则表达式的控制标记
- re.search(pattern,string,flags=0)
- string:待匹配字符串
- flags:控制标记
- re.match(pattern,string,flags=0)
- 参数定义相同
- re.spilt(pattern,string,maxsplit=0,flags=0)
- 增加一个新的参数, 表示最大分割数, 其余部分作为最后一个元素输出
- re.finditer(pattern,string,flags=0)
- 参数定义相同, 返回迭代结果, 从而可以用 for in的形式遍历
- re.sub(pattern,repl,string,conut=0,flag=0)
- repl:需要匹配替换的字符串
- count:替换的最大次数
上述返回Match对象的函数如果没有匹配, 则返回None, 从而可以直接使用if语句进行判断是否匹配. 上述标记, 如果在编译字符串的时候就指定, 则函数调用的时候, 就无需再次指定
Match类简介
方法/属性 | 目的 |
---|---|
group() | 返回被正则表达式匹配到的字符串 |
start() | 返回匹配的子字符串在字符串中的开始位置 |
end() | 返回匹配的子字符串在字符串中的结束位置 |
span() | 等价于(start(),end()) |
.string | 待匹配字符串 |
.re | 匹配时使用的正则表达式 |
.pos | 正则表达式搜索文本的开始位置 |
.endpos | 正则表达式搜索文本的结束位置 |
flags常用标记
常用标记(简写/全称) | 说明 |
---|---|
re.ASCII/re.A | 使\w,\b,\s和\d只匹配ASCII字符 |
re.I/re.IGNORECASE | 忽略正则表达式大小写 |
re.M/re.MULTILINE | 使得正则表达式中的^从给定字符串的每一行开始匹配 |
re.S/re.DOTALL | 使得.也可以匹配\n字符 |
re.VERBOSE/re.X | 使正则表达式可以附加解释信息 |
正则表达式的两种调用方法
- 函数式用法
re.search(...)
- 面向对象用法
- 编译后进行多次操作
1
2pat = re.compile(表达式)
rst = pat.search(...) - 因为已经编译了, 所以各个函数, 相比于原来的函数, 就需要去掉表示正则表达式的参数
- 编译后进行多次操作
说明:得益于解释器缓存, 同一个正则表达式, 使用函数式调用时, 不会被多次编译, 因此两种方式的消耗基本相同
VERBOSE模式实例
1 | charref = re.compile(r''' |
分组
- 使用 “(“ 和 “)”可以对一个正则表达式分组, 从而提取出正则表达式匹配的字符串中的部分内容
1
2
3
4
5
6
7
8
9
10
11match("(a(b)c)d","abcd") m = re.
0) m.group(
'abcd'
1) m.group(
'abc'
2) m.group(
'b'
2,0,2) m.group(
('b', 'abcd', 'b')
m.groups()
('abc', 'b') - 在字符串中, 从左向右每遇到一个括号, 序号+1. 使用gruop(i)表示提取第i个括号中匹配的内容
- 0表示匹配字符串本身, 所以无论正则表达式中是否含有分组, gruop(0)都是存在的
- 接受多个参数时, 返回多个参数对于的内容的元组
- 使用groups()返回所有分组匹配的字符串组成的元组(因此不包含直接匹配的正则表达式)
逆向引用(Backreferences)
- 在一个正则表达式中, 可以使用
\1
,\2
等由\
加上一个数字来引用前面出现的分组,表示此处需要匹配前面分组匹配的字符串1
2
3compile(r"(\b\w+)\s+\1") p = re.
"Paris in the the spring").group() p.search(
'the the'
括号中需要匹配一个单词, 此后\1表示此处匹配一个和括号相同的单词
Python的扩展正则表达式
注意:本节内容是正则表达式的扩展用法, 并非标准正则表达式语法
扩展正则表达式符号
符号 | 作用 |
---|---|
(?...) |
匹配…中的字符串, 但是不再捕捉其中的内容(语义标记) |
(?P<name>...) |
匹配…中的字符串, 同时此分组被命名为name |
先行断言
先行断言(Lookahead Assertion)是一种特殊的判断方法, 有正向和负向两种方式, 具体如下表
断言表示 | 类型 | 含义 |
---|---|---|
(?=…) | 正向 | 匹配…中的正则表达式, 但是不消耗实际字符串的位置, 为真时, 才继续匹配 |
(?!…) | 负向 | 匹配…中的正则表达式, 当与实际的字符串不匹配时为真, 否则整个正则表达式直接不匹配 |
扩展阅读
修改字符串
Python字符串相关函数
方法 | 目的 |
---|---|
spilt() | 分割字符串, 在匹配正则表达式的字符串处进行分割 |
sub() | 查找匹配正则表达式的子字符串, 并替换为指定的字符串 |
subn() | 和sub()函数效果相同, 增加额外的返回数据参数显示最大匹配次数 |
- spilt(string[,maxsplit=0])
- string:待匹配字符串
- maxspilt:最大分割数
- 如果正则表达式中含有捕捉分组, 则每次捕捉的结果会一同返回, 并且正好在两个分割字符串的结果之间
- sub(replacement,string[,count=0])
- replacement:替换成的字符串
- string:待替换字符串
- count:最大替换次数
- 返回替换后的字符串, 如果没有匹配, 返回原来的字符串
- subn()
- 参数和sub()相同
- 返回一个有两个元素的元组, 第一个元素是替换后的字符串, 第二个元素是替换次数
- 其他说明
- sub函数高级用法
- 在sub函数的relpacement中, 也可以使用\1,\2等引用正则表达式中的捕捉
- 如果使用了命名分组, 也可以使用
\g<name>
来应用, 注意<>
是必须的 - 使用
\g<2>
与\2
相同, 但可以减少歧义 - relpacement也可以是一个接受match对象的函数, 从而实现更加复杂的功能
- sub函数高级用法
高级用法实例代码
1 | def hexrepl(match): |
正则表达式最佳实践
- 使用正则表达式还是字符串方法
- 如果是无差别的文本替换, 应该使用字符串的replace()方法
- 如果是无差别的单一字符替换, 应该使用字符串的translate()方法
- 只有当替换操作是特异性的时候, 才应该考虑代价更高的正则表达式方法
- match()还是search()
- match()只从开始匹配, search()匹配任意位置
- 只有在确实需要从开头开始匹配, 才应该使用match(), 不要执着于非要只使用match()
- 正则表达式引擎会使用正则表达式的第一个确定字符进行匹配优化
- 贪婪匹配还是最小匹配
- 通常的重复匹配字符串都是贪婪匹配的, 即匹配尽可能长的字符串
- 在各种重复匹配符后加上一个?表示最小匹配, 例如+?,*?,??或者{m,n}?
- 最小匹配匹配尽可能短的字符串
- 使用re.VERBOSE
- 复杂的正则表达式的可读性较低, 使用测此标记可以增加表达式的可读性
- 处理字符类中的空白字符, 正则表达式中的所有空白都会被忽略
- 使用#添加注释
经典正则表达式实例
正则表达式 | 解释 |
---|---|
^[A-Za-z]+$ |
由26个字母组成的字符串 |
^[A-Za-z0-9]+$ |
由26个字母和数字组成的字符串 |
^-?\d+$ |
整数形式的字符串 |
^[0-9]*[1-9][0-9]*$ |
正整数形式的字符串 |
[\u4e00-\u9fa5] |
判断是不是中文字符 |
高级正则表达式实例
1 | \s* #Skip leading whitespace |
最后更新: 2024年04月18日 13:26
版权声明:本文为原创文章,转载请注明出处
原始链接: https://lizec.top/2017/08/08/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%AC%94%E8%AE%B0/