正则表达式-进阶

接上篇,正则表达式的基本内容并不多,也许你以为你对正则表达式已经完全掌握了,那么我们来看一个例子:

r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*")'
r'@(?:[A-Z0-9](?:[A-Z0-9-]{0,247}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,}(?<!-))$'

为了显示好看,分成了三排,上面这段正则表达式表示了对邮箱的验证,摘自Django源代码

这段正则的难易取决于大家自己的水平,但至少这段代码写的是比较复杂的,也警告着我们正则表达式还有很多细节需要我们的注意,记录如下

.

匹配任何字符,不包括换行,在DOTALL模式下,可以匹配换行

^和$

匹配开头和结尾,在MULTILINE模式下将匹配每一行的开头和结尾

{m,n}

匹配前一表达式重复m到n次,当忽略m的时候{,n}将匹配0到n个,当忽略n时{m,}将匹配m到无限多个

贪婪与非贪婪

[]

|

先尝试匹配|左边的表达式,然后是右边。左右边界直到找到一个()为止,没有将找到边界

(...)

(?iLmsux)

设置flag:re.I (ignore case), re.L (locale dependent), re.M (multi-line), re.S (dot matches all), re.U (Unicode dependent), and re.X

(?:...)

只抬高匹配优先级,但不放入re.group中

(?P...)

为group定名,可以在后面的表达式中使用,如:(?P<quote>['"]).*?(?P=quote),匹配双引号包含或单引号包含的字符串

(?P=name)

引用在之前定名的group,示例见上

(?#...)

注释,将被完全忽略

断言

(?(id/name)yes-pattern|no-pattern)

如果给定id或name的group存在,将匹配yes-pattern,否则将匹配no-pattern,如(<)?(\w+@\w+(?:\.\w+)+)(?(1)>)可以匹配<zhangdi@163.com>zhangdi@163.com但是不会匹配<zhangdi@163.com

\number

(?P=name)相似,按id引用之前的group,正则中group将从1开始按id编号,例子:(.+)[.]\1将匹配55.55the.the但不会匹配thethe

下面解释一下最头部那个例子

(
这是一个括号
^ [-!#$%&'*+/=?^_`{}|~0-9A-Z]+
开始符 可见字符中的1到多个
(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*
起始为一个点的可见字符0个到多个组合
|
或者,下面换了一种开头
^ "
开始符 双引号开头
([\001-\010\013\014\016-\037!#-\[\]-\177]
|\\[\001-\011\013\014\016-\177]
去掉了垂直制表等特殊字符外的字符以反斜杠开头就可以用垂直制表的字符集
)*"
0到多个双引号结束

括号结束,到此为止,该正则表达式的所匹配的两种开头表述结束,以上部分可称为user_regex
@
@符承上启下
(?:[A-Z0-9](?:[A-Z0-9-]{0,247}[A-Z0-9])?\.)+
以大写字母或数字开头和结尾的,中间包含0到247个大写字母或数字的组合,1到多个,总是以点结束
(?:[A-Z]{2,6}| [A-Z0-9-]{2,}(?<!-))$
2到6个大写字母2个以上包括短横杠的大写字母与数字组合,不能以短横杠开头

扩展

[1] 正则表达式在线验证

参考

[1] Python官方文档