则表达式(Regular Expression)是⼀种⽂本模式,使⽤单个字符串来描述、匹配⼀系列匹配某个句法规则的字符串。它繁琐也强⼤,⼏乎所有编程语⾔都⽀持利⽤正则表达式进⾏字符串操作。认真学习,勤动⼿。加上应⽤的时候进⾏⼀定的参考,掌握正则表达式不是问题。
字符
正则表达式的基本组成元素可以分为:字符和元字符。字符就是基础的计算机字符编码,通常正则表达式⾥⾯使⽤的就是数字、英⽂字⺟。⽽元字符,也被称为特殊字符,是⼀些⽤来表示特殊语义的字符。如^表示⾮,|表示或等。
单个字符
最简单的正则表达式可以由简单的数字和字⺟组成,没有特殊的语义,纯粹就是⼀⼀对应的关系。如想在'apple'这个单词⾥找到‘a'这个字符,就直接⽤ /a/ 这个正则就可以了。
但是如果想要匹配特殊字符的话,就要⽤到了元字符 \ , 它是转义字符,顾名思义,就是让其后续的字符失去其本来的含义。举个例⼦:我想匹配 * 这个符号,由于 * 这个符号本身是个特殊字符,所以我要利⽤转义元字符 \ 来让它失去其本来的含义: /\*/
如果本来这个字符不是特殊字符,使⽤转义符号就会让它拥有特殊的含义。我们常常需要匹配⼀些特殊字符,⽐如
换⾏符 \n ,制⻚符 \f ,回⻋ \r ,空⽩ \s 等, ⽽这些就需要我们使⽤转义字符来匹配。
多个字符
单个字符的映射关系是⼀对⼀的,即正则表达式的被⽤来筛选匹配的字符只有⼀个。要是想实现⼀对多的匹配,只要引⼊集合区间和通配符的⽅式就可以了。
集合的定义⽅式使⽤中括号 [] 和元字符 - 来表示区间范围, /[0-9]/ 就能匹配所有的数字, /[a-z]/ 则可以匹配
所有的英⽂⼩写字⺟。
同时正则表达式⾥也提供⼀批⽤来同时匹配多个字符的简便正则表达式:
重复
实现多个字符的匹配我们只要多次循环,重复使⽤我们的之前的正则规则就可以了。那么根据循环次数的多与少,
我们可以分为0次,1次,多次,特定次。
0|1
元字符? 代表了匹配⼀个字符或0个字符。设想⼀下,如果你要匹配color 和colour 这两个单词,就需要同时保
证u 这个字符是否出现都能被匹配到。所以你的正则表达式应该是这样的: /colou?r/ 。
>=0
元字符* 来表示匹配0个字符或数个字符。通常来过滤某些可有可的字符串。
>=1
元字符+ 适⽤于要匹配同个字符出现1次或多次的情况。
特定次数
在某些情况下,我们需要匹配特定的重复次数,元字符{ 和} 来给重复匹配设置精确的区间范围。
位置边界
当我们想在章或句中将特定单词找出来。这个时候需要使\b 。举个例:
The cat scattered his food all over the room.
我想找到 cat 这个单词,但是如果只是使/cat/ 这个正则,就会同时匹配到 cat 和 scattered 这两处本。我们使 /\bcat\b/ 这样就能匹配到 cat 这个单词了。
字符串边界
如果我们想匹配整个字符串的边界。需要到元字符 ^ 来匹配字符串的开头,元字符 $ 来匹配字符串的末尾。注意的是在本,如果要排除换符的扰,我们要使多模式。试着匹配 I am scq000 这个句:
我们可以使 /^I am scq000\.$/m 这样的正则表达式,其实m是multiple line的字。正则的模式除了m
外较常的还有i和g。前者的意思是忽略写,后者的意思是找到所有符合的匹配。
表达式
从简单到复杂的正则表达式演变通常要采分组、回溯引和逻辑处理的思想。利这三种规则,可以推演出限复杂的正则表达式。
分组
其中分组体现在:所有以( 和) 元字符所包含的正则表达式被分为组,每个分组都是个表达式,它也是构成级正则表达式的基础。如果只是使简单的(regex) 匹配语法本质上和不分组是样的,如果要发挥它强的作,往往要结合回溯引的式。
回溯引
所谓回溯引(backreference)指的是模式的后⾯部分引前已经匹配到的字符串。你可以把它想象成是变量,回溯引⽤的语法像\1 , \2 ,....,其中\1 表示引⽤的第个表达式, \2 表示引的第个表达式,以此类推。\0 则表示整个表达式。当我们需要限制回溯引的适范围。这个时候就通过前向查找和后向查找就可以达到这个的。
前向查找
前向查找(lookahead)是⽤来限制后缀的。凡是以(?=regex) 包含的⼦表达式在匹配过程中都会⽤来限制前⾯的表达式的匹配。例如happy happily 这两个单词,我想获得以happ 开头的副词,那么就可以使⽤happ(?=ily) 来匹配。如果我想过滤所有以happ 开头的副词,那么也可以采⽤负前向查找的正则happ(?!ily) ,就会匹配到happy 单词的happ 前缀。
我们分别对happy 、happily 前向查找会得到:
我们分别对happy 、happily 负前向查找会得到:
后向查找
后向查找(lookbehind)是通过指定⼀个⼦表达式,然后从符合这个⼦表达式的位置出发开始查找符合规则的字串。
举个简单的例⼦: apple 和 people 都包含 ple 这个后缀,那么如果我只想找到 apple 的 ple ,该怎么做呢?我
们可以通过限制 ap 这个前缀,就能唯⼀确定 ple 这个单词了。
其中 (?<=regex) 的语法就是我们这⾥要介绍的后向查找。 regex 指代的⼦表达式会作为限制项进⾏匹配,匹配
到这个表达式后,就会继续向后查找。另外种限制匹配是利 (?<!regex) 语法,这称为负后向查找。与
正前向查找不同的是,被指定的⼦表达式不能被匹配到。于是,在上的例中,如果想要查找 apple 的 ple 也
可以这么写成 /(?<!peo)ple 。
我们分别对 apple 、 people 后向查找会得到:
我们分别对 apple 、 people 负后向查找会得到:
贪婪与懒惰
正则表达式中包含能接受重复的限定符时,通常的为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例: a.*b ,它将会匹配最的以a开始,以b结束的字符串。如果它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前给出的限定符都可以被转化为懒惰匹配模式,只要在它后加上个问号?。这样 .*? 就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使最少的重复。现在看看懒惰版的例吧:
.*?b 匹配最短的,以a开始,以b结束的字符串。如果把它应于aabab的话,它会匹配aab(第⼀到第三个字符)和ab(第四到第五个字符)。
总结
最后,总结下我们在开发中的⼀些场景通过使正则表达式能更有效的解决:
△测试字符串内的模式。例如,可以测试输字符串,以查看字符串内是否出现电话号码模式或信卡号码模式。这称为数据验证。
△替换本。可以使正则表达式来识别档中的特定本,完全删除该本或者其他本替换它。
△基于模式匹配从字符串中提取字符串。可以查找档内或输域内特定的本。