1.元字符
①方括号 [ ]:指定一个字符类用于存放你需要匹配的字符集合
[abc] 会匹配字符 a,b 或 c;
[a-c] 可以实现相同的功能
[akm$] 会匹配任何字符 'a','k','m' 或 '$','$' 是一个元字符,但在方括号中它不表示特殊含义,它只匹配 '$'字符本身。
[^5] 会匹配除了 '5' 之外的任何字符
②反斜杠\:如果在反斜杠后边紧跟着一个元字符,那么元字符的“特殊功能”也不会被触发
例如需要匹配符号 [ 或 \,可以在它们前面加上一个反斜杠,以消除它们的特殊功能:\[,\\。
反斜杠后边跟一些字符还可以表示特殊的意义
其中d:digit,s:space,w:word
它们可以包含在一个字符类中,并且一样拥有特殊含义。例如 [\s,.] 是一个字符类,它将匹配任何空白字符(/s 的特殊含义),',' 或 '.'。
为避免反斜杠冗余的情况,对于原字符串,需要在其前面加上r。
③ * :用于指定前一个字符匹配零次或者多次。
例如 ca*t 将匹配 ct(0 个字符 a),cat(1 个字符 a),caaat(3 个字符 a),等等。
注:正则匹配是贪婪的,在开始时尽可能匹配多的内容,再进行回退。
如 a[bcd]*b匹配abcbd,首先匹配到a,然后在匹配 [bcd]*这一部分时,由于是尽可能多的匹配,会直接匹配到字符串结尾,
再进一步匹配b时,发现不满足,就会回退字符串再次尝试匹配b,这里就是回退到d,匹配不成又回退到b,匹配成功,返回结果。
④ + :用于指定前一个字符匹配一次或者多次。
要特别注意 * 和 + 的区别:* 匹配的是零次或者多次,所以被重复的内容可能压根儿不会出现;+ 至少需要出现一次。例如 ca+t 会匹配 cat 和 caaat,但不会匹配 ct。
⑤ ? :用于指定前一个字符匹配零次或者一次。
⑥ {m,n} :它的含义是前一个字符必须匹配 m 次到 n 次之间。
{,n} 相当于 {0,n};如果是 {m,} 相当于 {m,+无穷};如果是 {n},则是重复前一个字符 n 次。
⑦ | :
或操作符,对两个正则表达式进行或操作。如果 A 和 B 是正则表达式,A | B 会匹配 A 或 B 中出现的任何字符。为了能够更加合理的工作,| 的优先级非常低。例如 Fish|C 应该匹配 Fish 或 C,而不是匹配 Fis,然后一个 'h' 或 'C'。
⑧ ^ :
匹配字符串的起始位置。如果设置了 MULTILINE 标志,就会变成匹配每一行的起始位置。在 MULTILINE 中,每当遇到换行符就会立刻进行匹配。
re.search('^From', 'From Here to Eternity')
#结果:<_sre.SRE_Match object; span=(0, 4), match='From'>
re.search('^From', 'Reciting From Memory')
#结果:None
⑨ $ :匹配字符串的结束位置,每当遇到换行符也会离开进行匹配。
⑩ \A,\Z:
只匹配字符串的起始位置。如果没有设置 MULTILINE 标志的时候(即re.M),\A 和 ^ 的功能是一样的;但如果设置了 MULTILINE 标志,则会有一些不同:\A 还是匹配字符串的起始位置,但 ^ 会对字符串中的每一行都进行匹配。
⑪\b:单词边界,这是一个只匹配单词的开始和结尾的零宽断言。“单词”定义为一个字母数字的序列,所以单词的结束指的是空格或者非字母数字的字符。
- >>> p = re.compile(r'\bclass\b')
- >>> print(p.search('no class at all'))
- <_sre.SRE_Match object; span=(3, 8), match='class'>
- >>> print(p.search('the declassified algorithm'))
- None
- >>> print(p.search('one subclass is'))
- None
⑫ ():分组符
- >> p = re.compile('(a(b)c)d')
- >>> m = p.match('abcd')
- >>> m.group(0)
- 'abcd'
- >>> m.group(1)
- 'abc'
- >>> m.group(2)
- 'b'
- >>> m.groups()
- ('abc', 'b')
⑬ \1,\2...:
\1 表示引用前边成功匹配的序号为 1 的子组。
- >>> p = re.compile(r'(\b\w+)\s+\1')
- >>> p.search('Paris in the the spring').group()
- 'the the'
2.方法
注意,由于方法可能会因无结果,后续使用group时可配合try使用,也可以利用if判断是否有匹配对象返回。
使用过程:先进行compile编译,再利用编译后的变量调用函数。
如:
p = re.compile('[a-z]+')
result = p.match("aaa")
结果:
<_sre.SRE_Match object; span=(0, 5), match='aaa'>
返回的是一个匹配对象,而匹配对象还有对应的方法。
如果不使用编译模式,也可以直接使用re的全局函数,如re.match(r'\s+', 'aa aa'),即第一个为正则字符串,第二个为匹配的字符串,当然,这种速度相对较慢。
3.匹配对象
4.re.
①re.X
这个选项忽略规则表达式中的空白和注释,并允许使用 ’#’ 来引导一个注释。这样可以让你把规则写得更美观些。
rc = re.compile(r"""
# start a rule
/d+
# number
|
[a-zA-Z]+
# word
""", re.X)
res = rc.match('aaaa')
# print(res)
print(res.group())
②re.I
忽略大小写
③re.S
使得 . 可以匹配任何字符,包括换行符。如果不使用这个标志,. 将匹配除了换行符的所有字符。
a = """sdfkhellolsdlfsdfiooefo:
877898989worldafdsf"""
b = re.findall('hello(.*?)world',a)
c = re.findall('hello(.*?)world',a,re.S)
print ('b is ' , b)
print ('c is ' , c)
# 输出结果:
# b is []
# c is ['lsdlfsdfiooefo:\n877898989']
④re.A
使得 \w,\W,\b,\B,\s 和 \S 只匹配 ASCII 字符,而不匹配完整的 Unicode 字符。这个标志仅对 Unicode 模式有意义,并忽略字节模式。
⑤re.L
LOCALE
使得 \w,\W,\b 和 \B 依赖当前的语言(区域)环境,而不是 Unicode 数据库。
区域设置是 C 语言的一个功能,主要作用是消除不同语言之间的差异。例如你正在处理的是法文文本,你想使用 \w+ 来匹配单词,但是 \w 只是匹配 [A-Za-z] 中的单词,并不会匹配 'é' 或 'ç'。如果你的系统正确的设置了法语区域环境,那么 C 语言的函数就会告诉程序 'é' 或 'ç' 也应该被认为是一个字符。当编译正则表达式的时候设置了 LOCALE 的标志,\w+ 就可以识别法文了,但速度多少会受到影响。
⑥re.M
通常 ^ 只匹配字符串的开头,而 $ 则匹配字符串的结尾。当这个标志被设置的时候,^ 不仅匹配字符串的开头,还匹配每一行的行首;& 不仅匹配字符串的结尾,还匹配每一行的行尾。
5.group与groups
m = re.search(r"([0-9])*", "123")
print(m.groups())
# 结果:('3',) 原因:[0-9]是一个字符,由于贪婪匹配,会尽可能匹配到最后的3
m = re.search(r"([0-9])*", "123")
print(m.group())
# 结果:123 返回整个匹配的字符串而非括号内的分组
6.非捕获组和命名组
①非捕获组
有时候只是需要用一个组来表示部分正则表达式,并不需要这个组去匹配任何东西,这时可以通过非捕获组来明确表示意图。非捕获组的语法是 (?:...),这个 ... 你可以替换为任何正则表达式。
m = re.search(r"1(?:[abc])+1", "1abc1") #注意养成良好的加r习惯
print(m.group())
②命名组
命名组的语法是 Python 特有的扩展语法:(?P<name>)。很明显,< > 里边的 name 就是命名组的名字啦。命名组除了有一个名字标识之外,跟其他捕获组是一样的。
匹配对象的所有方法不仅可以处理那些由数字引用的捕获组,还可以处理通过字符串引用的命名组。除了使用名字访问,命名组仍然可以使用数字序号进行访问:
- >>> p = re.compile(r'(?P<word>\b\w+\b)')
- >>> m = p.search( '(((( Lots of punctuation )))' )
- >>> m.group('word')
- 'Lots'
- >>> m.group(1)
- 'Lots'
7.扩展机制
①前向断言(?=...)
前向肯定断言。如果当前包含的正则表达式(这里以 ... 表示)在当前位置成功匹配,则代表成功,否则失败。一旦该部分正则表达式被匹配引擎尝试过,就不会继续进行匹配了;剩下的模式在此断言开始的地方继续尝试。
②前向否定断言(?!...)
前向否定断言。这跟前向肯定断言相反(不匹配则表示成功,匹配表示失败)。
例如想匹配扩展名不是 bat 的文件,使用.*[.](?!bat$).*$即可
如果正则表达式 bat 在当前位置不匹配,尝试剩下的部分正则表达式;如果 bat 匹配成功,整个正则表达式将会失败(因为是前向否定断言嘛^_^)。(?!bat$) 末尾的 $ 是为了确保可以正常匹配像 sample.batch 这种以 bat 开始的扩展名。
同样,有了前向否定断言,要同时排除 bat 和 exe 扩展名,也变得相当容易:
.*[.](?!bat$|exe$).*$