正则表达式
正则表达式与程序语言无关。正则表达式做匹配实际上就做3件事:【字符匹配】+【次数匹配】+【逻辑匹配】
下面分别进行叙述
正则表达式中的字符匹配
字符匹配可以通过通配符匹配实现,也可以通过[]集合匹配实现,而[]集合是更加直观的一种
-
通配符匹配
- . 匹配除换行符外的任意单个字符(万能符)
- \d 匹配任意单个数字
- \w 匹配任意单个字母
- \s 匹配任意单个空白字符,如空格、制表符(\t)、换行符(\n)等
-
基于[]表达式的自定义集合匹配
使用方括号[]包含若干个字符,可以匹配[]集合中的任意一个字符;用 [^ ] 包含一系列字符,则能够匹配除[]集合字符外的任意单个字符。注意,都是匹配单个字符
eg.
[abc]可以匹配'a', 'b', 'c'的任意一个
[a-z]可以匹配任意一个小写字母
[a-zA-Z]可以匹配任意一个字母
[a-zA-Z0-9]可以匹配任意一个字母或数字
[^a-zA-Z0-9]可以匹配任意一个非数字且非字母的字符
注意,在方括号[]中,除了^表示取反外,一切字符都表示字符本身,没有特殊功能,小括号()在[]中也只表示字符 '(' 和 ')',没有分组功能
正则表达式中的次数匹配
相似地,次数匹配可以使用通配符匹配,也可以使用自定义{}表达式匹配
-
次数通配符匹配
-
? 前置表达式出现0次或者1次,相当于 {0,1},好像在问“出现还是不出现?”。比如:"a[cd]?"可以匹配 "a","ac","ad"
-
+ 前置表达式至少出现1次,相当于 {1,},可理解为在1的基础上可以一直+下去。比如: "a+b"可以匹配 "ab","aab","aaab"...
-
* 前置表达式出现任意次,相当于 {0,},比如: "a*b"可以匹配 "b","aaab"...
-
-
自定义{}表达式匹配
使用{}表达式做次数匹配更加直观,也更加灵活,可以自定义次数的上下界,个人更喜欢用
{n}表示前置表达式重复n次
{m,n}表示前置表达式至少重复m次,至多重复n次,左右都是闭区间
{m,}表示前置表达式至少重复m次
正则表达式中的逻辑匹配
逻辑匹配指的是,对字符串中的字符间的逻辑关系、位置关系、组别关系等进行匹配。逻辑匹配不匹配任何字符,也不匹配次数
表达式 | 作用 |
---|---|
() | 在正则表达式中()用来实现分组。括号中的表达式将作为一个整体看待,在获取匹配结果时,小括号包含的表达式所匹配到的字符串可以单独获取。如:表达式 "¥(\d+\.?\d*)" 在匹配 "$10.9,¥20.5" 时,匹配到的内容是:"¥20.5";单独获取括号范围匹配到的内容是:"20.5"。注意note:正则表达式中的()不匹配任何字符而仅作为分组,如果需要匹配字符串中的小括号,需要使用\(和\) |
^ | 与目标字符串开始的地方匹配,不匹配任何字符 |
$ | 与目标字符串结束的地方匹配,不匹配任何字符 |
\b | 匹配一个单词的边界,它要求它在匹配结果中所处位置的左右两边,其中一边是 "\w" 范围,另一边是 非"\w" 的范围。同样不匹配任何字符 |
| | 表示正则表达式之间的 "或" 关系,如'a|b',表示匹配a也行,匹配b也行 |
正则表达式的高阶用法
-
贪婪匹配和非贪婪匹配
次数表达式在匹配过程中,默认总是尽可能多的匹配,即默认贪婪匹配。事实上,贪婪匹配并不适用于所有的情况。
如,字符串'哈哈哈哈哈',若想通过正则表达式确定其最大重复单元,那么使用正则表达式 '(.+)\1+' 捕获分组可以得到'哈哈';但如果我们需要确定最小重复单元,就需要分组能够命中的字符串长度尽可能少,也就是使用非贪婪匹配
在匹配次数表达式(?、 +、 *、{m, n})后再加上一个 "?" 号,可以使匹配次数不定的表达式尽可能少的匹配,使可匹配可不匹配的表达式,尽可能的 "不去匹配"
因此,使用正则表达式 '(.+?)\1+' 或者 '(.{1,}?)\1+' 捕获分组可以得到最小重复单元'哈'
-
分组的捕获值的引用
"小括号包含的表达式所匹配到的字符串"--即分组的捕获值 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式可以引用前面的分组捕获值。引用方法是 "" 加上一个数字。"\1" 引用第1对括号内匹配到的字符串,"\2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 "(" 在前,那这一对就先排序号
如上面的非贪婪匹配提到的 '(.+?)\1+' 中 的\1表示的就是转义格式下的\1,从而实现对(.+?)捕获值的引用
关于正则表达式,还可参考http://www.regexlab.com/zh/regref.htm
python中的正则表达式
python中的re库实现了正则表达式操作
常用操作为search、findall和sub
-
re.search
在字符串中寻找被pattern命中的部分,返回首个命中部分的re.Match object,未命中则返回None
对于re.Match object,可以使用group()获取被整个pattern命中的字符串,使用groups()获取被pattern中各个()分组所命中的字符串,以tuple形式
例如:
>>> pattern = 'i love (.+)'
>>> s = 'xxx i love u'
>>> res = re.search(pattern, s)
>>> print(res)
<re.Match object; span=(4, 12), match='i love u'>
>>> res.group()
'i love u'
>>> res.groups()
('u',)
-
re.findall()
Return a list of all non-overlapping不重叠的 matches in the string.
If one or more capturing groups are present in the pattern 如果pattern里包含多个()分组, return
a list of groups; this will be a list of tuples if the pattern has more than one group.
Empty matches are included in the result.
如果pattern中不含分组,则返回被整个pattern命中的所有结果的list
如果pattern中包含分组,则返回被整个pattern命中的所有结果的分组tuple-list
例如:
# pattern中包含2个group,(\w+)和(\d{2}\.\d{2})
>>> results = re.findall('title="(\w+)".*?<p class="pl">.*?(\d{2}\.\d{2}).*?</p>', content, re.S)
>>> print(results)
[('追风筝的人', '29.00'), ('小王子', '22.00'), ('围城', '19.00')]
-
re.sub
re.sub(pattern, repl, string, count) 找到string中被整个patern命中的部分,使用repl替换,返回替换后的字符串
例如:
# (\w)\\1{2}的原型是(\w)\1{2},'\\1'是'\1'的转义,表示第一个分组匹配到的值
>>> pattern = '(\w)\\1{2}'
>>> s = 'xxx i love u'
>>> res = re.sub(pattern, '', s)
>>> res
' i love u'
网友评论