这是一篇发布时间大于两年的文章,当时的一些内容或笔者曾经的思维可能已不再适用于现在,请谨慎判断文章内容的可靠性


6.子表达式

正则表达式中的自表达式就是使用小括号对表达式进行分组归类等,如要匹配文本中的多个&nbps,使用&nbps{2,}会错误的匹配,只会匹配到多个s而不是&nbps,这里使用小括号将其包括起来:(&nbps){2,}就能成功匹配到多组给定字符集

  • ip 地址

(\d{1,3}\.){3}\d{1,3}

  • 年份

(19|20)\d{2}

  • 使用子表达式的嵌套完善 ip 地址匹配

上面对 ip 的匹配依然有很多缺陷,如超过 255 的三位数字也会匹配进去,我们了解到一个 ip 地址组成每一段的数组需要满足以下条件

  1. 任意以 1 位或 2 位数字
  2. 任意以 1 开头的三位数字
  3. 任意以 2 开头、第二位在 0-4 之间的三位数字
  4. 任意以 25 开头,第三位在 0-5 之间的三位数字

(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))

7.回溯引用

回溯引用允许正则表达式应用前面的匹配结果

  • 匹配连续两个相同的单词

[ ]+(\w+)[ ]+\1

这个表达式的回溯引用是末尾的\1,这里的\1表示的是第一个子表达式即前面小括号里面的匹配结果

  • 匹配 html 中的 h1-h6 标签

<[Hh]([1-6])>.*?</[Hh]\1>

这里使用回溯引用就不会错误地匹配到<h2></h3>中的内容

替换

8.前后查找

前面所述的正则匹配都是匹配指定满足的文本,而这里所使用的查找是匹配位于满足指定要求文本其相对位置的一段指定文本

向前查找

?=需要匹配的文本在后面,需要查找的文本在前面

  • 提取 url 中的协议名

.+(?=:)

向后查找

?<=

  • 提取$后的价格数字

(?<=\$)[\d.]+

前后查找组合

  • 匹配 html 标签<html></html>内的内容

(?>=<html>).*(?=</html>)

对前后查找取非

  • 向前查找与向前查找取非(即不与给定模式匹配的文本 ) (?=),(?!)

  • 向后查找与向后查找取非

(?<=),(?<!)

9.嵌入条件

(?(back-reference)true-regex|false-regex)

用于判断给定的前面的回溯表达式是否有过成功匹配,若有则继续进行判断正确的匹配,若没有则进行另一种匹配

  • 提取 img 标签,若 img 标签被 a 标签包括,则一起提取出来

(<a\s+[^>]+>\s*)?<img\s+[^>]+>(?(1)\s*</a>)

(<a\s+[^>]+>\s*)这一段首先匹配 a 开始标签以及其属性,后方可以包含任意多个空白字符,后面加上?表示 a 标签也可以不存在;<img\s+[^>]+>用于匹配 img 标签以及其属性;(?(1)\s*</a>)最后这个模式开始的?(1)条件判断即判断以第一个模式是否有匹配成功,若找到匹配则继续进行后面的模式匹配\s*</a>以寻找 a 的关闭标签

  • 匹配北美电话号码格式

(\()?\d{3}(?(1)\)|-)\d{3}-\d{4}

123-456-7890

(123)456-7890

(123)-456-7890

(123-456-7890

1234567890

123 456 7890

对于前后查找的条件判断

前后查找条件只在一个向前或者向后查找操作匹成功时允许接下来的匹配,前后查找条件判断的使用与前面使用方法类似,只需要将?后面的回溯引用表达式替换为一个完整的前后查找表达式即可

  • 美国邮编匹配

美国的 zip 邮编有两种正确的格式1111111111-2222

\d{5}(?(?=-)-\d{4})

这里\d{5}首先匹配前五位数字,后面(?(?=-)-\d{4})中前面部分?(?=-)用于判断向后查找-是否成功找到,若找到则使用-\d{4}匹配后面一个 dash 加四位数字

11111

22222

33333-

44444-5555