正则表达式--零宽断言

前言

正则表达式是编程中最常用的工具之一, 跟朋友聊天偶然得知正则表达式的新用法——零宽断言, 便花时间学习了一下, 顺便巩固正则表达式的基础知识. 本文主要介绍了正则表达式的常用元字符、零宽断言、以及常用正则表达式.

温故(基本符号)

元字符 作用
\ 将下一个字符标记符、或一个向后引用、或一个八进制转义符
^ 匹配输入字行首.如果设置了RegExp对象的Multiline属性, ^也匹配
$ 匹配输入行尾.如果设置了RegExp对象的Multiline属性, $也匹配
* 匹配前面的子表达式任意次
+ 匹配前面的子表达式一次或多次,等价于{1,}
? 匹配前面的子表达式零次或一次, 当该字符紧跟在任何一个其他限制符后面时, 匹配模式是非贪婪的(默认是贪婪模式).
{n,} 至少匹配n次
{n,m} 最少匹配n次且最多匹配m次
x|y 匹配x或y
[xyz] 字符集合.匹配所包含的任意一个字符
[^xyz] 负值字符集合.匹配未包含的任意字符
[a-z] 字符范围.匹配指定范围内的任意字符
[^a-z] 负值字符范围.匹配任何不在指定范围内的任意字符
\b 匹配一个单词的边界, 也就是指单词和空格间的位置
\B 匹配非单词边界
\cx 匹配由x指明的控制字符.例如, \cM匹配一个Control-M或回车符.x的值必须为A-Z或a-z之一.否则, 将c视为一个原义的"c"字符
\d 匹配一个数字字符.等价于[0-9]
\D 匹配一个非数字字符.等价于[^0-9]
\n 匹配一个换行符.等价于\x0a和\cJ
\r 匹配一个回车符.等价于\x0d和\cM
\s 匹配任何不可见字符, 包括空格、制表符、换页符等,等价于[\f\n\r\t\v]
\S 匹配任何可见字符.等价于[^\f\n\r\t\v]
\t 匹配一个制表符.等价于\x09和\cI
\v 匹配一个垂直制表符.等价于\x0b和\cK
\w 匹配包括下划线的任何单词字符.类似但不等价于[A-Za-z0-9_]
\W 匹配任何非单词字符.等价于[^A-Za-z0-9_]
() 分组并且将匹配这个表达式的字符保存(一个正则表达式中最多可以保存9个), 它们可以用 \1 到\9 的符号来引用

知新(零宽断言)

零宽断言用于查找在断言内容(但并不包括断言内容本身)之前或之后的东西, 也就是说它们像\b,^,$那样用于指定一个位置, 这个位置应该满足一定的条件(即断言), 而该位置不加入结果串, 所以在结果串中它的宽度为0, 因此它们被称为零宽断言

正向零宽断言

正向零宽断言用于查找结果串之前或之后存在断言内容的字符串.

  1. 零宽度正预测先行断言
1
[pattern](?=exp)

零宽度正预测先行断言是匹配以(?=exp)结尾的属于[pattern]的部分(匹配结果不包含(?=exp))

1
2
3
4
5
s = "You're my fantasy."
# 匹配以(?='re)结尾的[\S+]
re.findall(r"\S+(?='re)",s)     # ['You']
# 匹配以(?=\s)结尾的[\S+]
re.findall(r"\S+(?=\s)",s)      # ["You're", 'my']
  1. 零宽度正回顾后发断言
1
(?<=exp)[pattern]

零宽度正回顾后发断言是匹配以(?<=exp)开头的属于[pattern]的部分(匹配结果不包含(?<=exp))

1
2
3
4
5
s = "You're my fantasy."
# 匹配以(?<=You)开头的[\S+]
re.findall(r"(?<=You)\S+",s)     # ["'re"]
# 匹配以(?<=\s)开始的[\S+]
re.findall(r"(?<=\s)\S+",s)      #  ['my', 'fantasy.']

负向零宽断言

负向零宽断言用于查找结果串之前或之后不存在断言内容的字符串.

  1. 零宽度负预测先行断言
1
[pattern](?!exp)

零宽度负预测先行断言用于匹配结果串[pattern]后面不出现(?!exp)的字符串(匹配结果不包含(?!exp)).

1
2
3
4
5
s = "You're my fantasy."
# 匹配不以(?!')结尾的[\w+]
re.findall(r"\w+(?!')",s)     # ['Yo', 're', 'my', 'fantasy']   因 You以(?!')结尾所以丢弃部分
# 匹配不以 (?!\.) 结尾的[\w+]
 re.findall(r"\w+(?!\.)",s)      #   ['You', 're', 'my', 'fantas']  fantasy以(?!\.)结尾所以丢弃部分
  1. 零宽度负回顾后发断言
1
(?<!exp)[pattern]

零宽度负回顾后发断言用于匹配结果串[pattern]前面不出现(?<!exp)的字符串(匹配结果不包含?<!exp)).

1
2
3
s = "You're my fantasy."
# 匹配不以 (?<!\s) 开始的[\w+]
re.findall(r"(?<!\s)\w+",s)     #   ['You', 're', 'y', 'antasy']  因 my和 fantasy 以(?<!\s)开始所以丢弃部分

注意

回顾断言(?<=exp)(?<!exp)exp中不能使用不确定匹配次数的元字符, 也就是说不能使用元字符* + ? {n,} {n,m}但可以使用{6}.至于回顾断言能否放[pattern]右边和预测断言能否放[pattern]左边这种问题就不说了…

常用正则表达式

  1. 中文: /[\u4e00-\u9fa5]/
  2. 英文和数字: /^[A-Za-z0-9]+$/
  3. 整数: /^-?[1-9]\d*$/
  4. 数字: /^-?(\d+\.\d+|[1-9]d*|0)$/
  5. Email: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
  6. URL: /^(?:(?:(?:[a-z]+:)?\/\/)|www\.)(?:\S+(?::\S*)?@)?(?:localhost|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3})|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#][^\s"]*)?$/
  7. 中国大陆手机号: /^1[345678]\d{9}$/
  8. 中国大陆18位身份证号: /^[1-9]\d{5}(?:18|19|20)\d{2}(?:(?:0[1-9])|(?:1[0-2]))(?:(?:[0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
  9. 中国大陆电话: /^\d{3}-\d{8}|\d{4}-\{7,8}$/
  10. IPV4: /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/
  11. IPV6: /^((?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(:[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(:[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(:[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(:[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(:[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(:[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(:[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(:[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(:[a-fA-F\d]{1,4}){1,6}|:)|(?::((?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(%[0-9a-zA-Z]{1,})?$/
  12. MD5: /^[a-f0-9]{32}|[A-F0-9]{32}$/
  13. 日期(YYYY/MM/DDYYYY/MM/DD HH:mm:SS): /^\d{4}[/.-]\d{1,2}[/.-]\d{1,2}(?:\s\d{1,2}:\d{1,2}:\d{1,2})?$/