正则表达式全解析

正则表达式定义

  • 正则表达式(regular expression)就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。
  • 正则表达式可以用来:
    • 验证字符串是否符合指定特征,比如验证是否是合法的邮件地址。
    • 用来查找字符串,从一个长的文本中查找符合指定特征的字符串,比查找固定字符串更加灵活方便。
    • 用来替换,比普通的替换更强大。

符号介绍

普通字符和简单的转义字符

  • 普通字符
    • 字母、数字、汉字、下划线、以及没有特殊定义的标点符号,都是"普通字符"。
    • 匹配与之相同的一个字符。
  • 简单的转义字符
    • \r,\n代表回车和换行符
    • \t 制表符
    • \\ 代表"\" 本身
    • 这些转义字符的匹配方法与 "普通字符" 是类似的。也是匹配与之相同的一个字符。

能够与 ‘多种字符’ 匹配的表达式

  • \d 任意一个数字,0~9 中的任意一个
  • \w 任意一个字母或数字或下划线,也就是 A~Z,a~z,0~9,_ 中任意一个
  • \s 包括空格、制表符、换页符等空白字符的其中任意一个
  • . 小数点可以匹配除了换行符(\n)以外的任意一个字符

虽然可以匹配其中任意字符,但是只能是一个,不是多个。

自定义能够匹配 '多种字符' 的表达式

  • 使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。

例如:[ab5@] 匹配 "a" 或 "b" 或 "5" 或 "@"

[^A-F0-3] 匹配 "A"~"F","0"~"3" 之外的任意一个字符

同样,虽然可以匹配其中任意一个,但是只能是一个,不是多个。

修饰匹配次数的特殊符号

可以让表达式重复匹配的符号。放在“被修饰的表达式”后边。

  • {n} 表达式重复n次
  • {m,n}表达式至少重复m次,最多重复n次
  • {m,} 表达式至少重复m次
  • ? 匹配表达式0次或者1次,相当于 {0,1}
  • +表达式至少出现1次,相当于 {1,}
  • * 表达式不出现或出现任意次,相当于 {0,}

举例:表达式 "\d+\.?\d*" 在匹配 "It costs $12.5" 时,匹配的结果是:成功;匹配到的内容是:"12.5";

一些符号在表达式中代表抽象的特殊意义

  • ^ 与字符串开始的地方匹配,不匹配任何字符
  • $ 与字符串结束的地方匹配,不匹配任何字符
  • \b 匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符

举例1:表达式 “^aaa” 在匹配 “xxx aaa xxx” 时,匹配结果是:失败。因为 “^” 要求与字符串开始的地方匹配,因此,只有当 “aaa” 位于字符串的开头的时候,“^aaa” 才能匹配。

举例2:表达式 “.\b.” 在匹配 “@@@abc” 时,匹配结果是:成功;匹配到的内容是:“@a”。
进一步说明:"\b" 与 "^" 和 "$" 类似,本身不匹配任何字符,但是它要求它在匹配结果中所处位置的左右两边,其中一边是 "\w" 范围,另一边是 非"\w" 的范围。

举例3:表达式 “\bend\b” 在匹配 “weekend,endfor,end” 时,匹配结果是:成功;匹配到的内容是:“end”。

一些符号可以影响表达式内部的子表达式之间的关系

  • | 左右两边表达式之间 "或" 关系,匹配左边或者右边
  • ( )
    • 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰
    • 取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到

举例1:表达式 “Tom|Jack” 在匹配字符串 “I‘m Tom, he is Jack” 时,匹配结果是:成功;匹配到的内容是:“Tom”。匹配下一个时,匹配结果是:成功;匹配到的内容是:“Jack”。

举例2:表达式 “(go\s*)+” 在匹配 “Let‘s go go go!” 时,匹配结果是:成功;匹配到内容是:“go go go”。

在表达式中有特殊意义,需要添加 “\” 才能匹配该字符本身的字符汇总

^ $ ( ) [ ] { } . ? + * |

高级规则

匹配次数中的贪婪与非贪婪

  • 贪婪模式
    • {m,}, “?”, “*”, “+"等在匹配的时候,总是尽可能多的匹配符合它规则的字符。

例如: (d)(\w+?)(d) 匹配 “dxxxdxxxd”时, "\w+" 将匹配第一个 "d" 和最后一个 "d" 之间的所有字符 "xxxdxxx"。

  • 非贪婪模式
    • 在修饰匹配次数的特殊符号后再加上一个 "?" 号,则可以使匹配次数不定的表达式尽可能少的匹配。这种匹配原则叫作 "非贪婪" 模式,也叫作 "勉强" 模式。

例如:(d)(\w+?)(d) 匹配“dxxxdxxxd”时,为了让整个表达式匹配成功,"\w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配,从而使整个表达式匹配成功。因此,结果是:"\w+?" 匹配 "xxx"

举例1:表达式 "<td>(.*)</td>" 与字符串 "<td><p>aa</p></td> <td><p>bb</p></td>" 匹配时,匹配的结果是:成功;匹配到的内容是 "<td><p>aa</p></td> <td><p>bb</p></td>" 整个字符串, 表达式中的 "</td>" 将与字符串中最后一个 "</td>" 匹配。

举例2:相比之下,表达式 "<td>(.*?)</td>" 匹配举例1中同样的字符串时,将只得到 "<td><p>aa</p></td>", 再次匹配下一个时,可以得到第二个 "<td><p>bb</p></td>"。

反向引用 \1, \2...

  • 表达式在匹配时,表达式引擎会将小括号 ( ) 包含的表达式所匹配到的字符串记录下来。其实,"小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。
  • 表达式后边的部分,可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "\" 加上一个数字。"\1" 引用第1对括号内匹配到的字符串,"\2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 "(" 在前,那这一对就先排序号。

举例1:表达式 "('|")(.*?)(\1)" 在匹配 " 'Hello', "World" " 时,匹配结果是:成功;匹配到的内容是:" 'Hello' "。再次匹配下一个时,可以匹配到 " "World" "。

举例2:表达式 "(\w)\1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 时,匹配结果是:成功;匹配到的内容是 "ccccc"。再次匹配下一个时,将得到 999999999。这个表达式要求 "\w" 范围的字符至少重复5次,注意与 "\w{5,}" 之间的区别。

举例3:表达式 "<(\w+)\s*(\w+(=('|").*?\4)?\s*)*>.*?</\1>" 在匹配 "<td id='td1' style="bgcolor:white"></td>" 时,匹配结果是成功。如果 "<td>" 与 "</td>" 不配对,则会匹配失败;如果改成其他配对,也可以匹配成功。

正向预搜索

前面几个代表抽象意义的特殊符号:“^”,“$”,“\b”。它们都有一个共同点,那就是:它们本身不匹配任何字符,只是对 “字符串的两头” 或者 “字符之间的缝隙” 附加了一个条件。预搜索则是对 “两头” 或者 “缝隙”

  • 正向预搜索:"(?=xxxxx)","(?!xxxxx)“
  • 格式:"(?=xxxxx)",在被匹配的字符串中,所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。

举例1:表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98, Windows NT, Windows 2000" 时,将只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字样则不被匹配。

举例2:表达式 "(\w)((?=\1\1\1)(\1))+" 在匹配字符串 "aaa ffffff 999999999" 时,将可以匹配6个"f"的前4个,可以匹配9个"9"的前7个。这个表达式可以读解成:重复4次以上的字母数字,则匹配其剩下最后2位之前的部分。

  • 格式:"(?!xxxxx)",所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。

举例3:表达式 "((?!\bstop\b).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时,将从头一直匹配到 “ stop " 之前的位置,如果字符串中没有 “ stop ",则匹配整个字符串。

举例4:表达式 "do(?!\w)" 在匹配字符串 "done, do, dog" 时,只能匹配 "do"。在本条举例中,"do" 后边使用 "(?!\w)" 和使用 "\b" 效果是一样的。

反向预搜索

  • 反向预搜索:"(?<=xxxxx)","(?<!xxxxx)"
  • 两种格式的概念和正向预搜索是类似的,反向预搜索要求的条件是:所在缝隙的 “左侧”,两种格式分别要求必须能够匹配和必须不能够匹配指定表达式。

举例5:表达式 "(?<=\d{4})\d+(?=\d{4})" 在匹配 "1234567890123456" 时,将匹配除了前4个数字和后4个数字之外的中间8个数字。

其他通用规则

  • 在表达式 "\s","\d","\w","\b" 表示特殊意义的同时,对应的大写字母表示相反的意义
    • \S 匹配所有非空白字符("\s" 可匹配各个空白字符)
    • \D 匹配所有的非数字字符
    • \W 匹配所有的字母、数字、下划线以外的字符
    • \B 匹配非单词边界,即左右两边都是 "\w" 范围或者左右两边都不是 "\w" 范围时的字符缝隙
  • 括号 "( )" 内的子表达式,如果希望匹配结果不进行记录供以后使用,可以使用 "(?:xxxxx)" 格式

举例1:表达式 "(?:(\w)\1)+" 匹配 "a bbccdd efg" 时,结果是 "bbccdd"。括号 "(?:)" 范围的匹配结果不进行记录,因此 "(\w)" 使用 "\1" 来引用。

注意事项

  • 表达式不要匹配空字符串。否则会一直得到匹配成功,而结果什么都没有匹配到。

比如:准备写一个匹配 "123"、"123."、"123.5"、".5" 这几种形式的表达式时,整数、小数点、小数数字都可以省略,但是不要将表达式写成:"\d*\.?\d*",因为如果什么都没有,这个表达式也可以匹配成功。更好的写法是:"\d+\.?\d*|\.\d+"。

  • 能匹配空字符串的子匹配不要循环无限次。

如果括号内的子表达式中的每一部分都可以匹配 0 次,而这个括号整体又可以匹配无限次,那么情况可能比上一条所说的更严重,匹配过程中可能死循环。

  • 或 "|" 的左右两边,对某个字符最好只有一边可以匹配,这样,不会因为 "|" 两边的表达式因为交换位置而有所不同。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值