正则表达式备忘录
什么是正则表达式?
正则表达式是一个从左向右去匹配目标字符串的一个模式,可以匹配部分字符也可以全部匹配。
/ brown fox/ | the quick brown fox jumps over the lazy dog |
/ .*?brown fox.*/ | the quick brown fox jumps over the lazy dog |
正则表达式在所有的语言里都一样吗?
不同的工具或者语言里,正则表达式语法并不完全相同,使用时需要参考目标环境。
正则表达式到底长什么样?
/[a-z]+(abc|xyz)*/i 就是一个简单的正则表达式。//是正则表达式模式的定界符,意思就是//中间的部分就是你写的模式。[],(),+, |,*就是正则表达式的元字符—可以简单理解是保留字,其中+,*也叫量词—就是定义匹配次数的。最后那个i叫做模式修正符—它定义模式的一些特殊规则,如是否区分大小写。正则表达式里还有一些概念,如子模式,逆向引用,重复,断言,注释等。
什么是模式修正符?
模式修正符就是来限定模式与目标串的匹配方式的。它区分大小写,其中的空格和换行符会会被忽略,预定义的修正符之外的字符会导致错误。常见的有i,m,s,x,U等。
需要注意的是:m多行模式和s单行模式不是互斥的。他们只是分别定义了. ^ $这三个元字符的匹配方式。设定了s的时候,句点.就匹配所有的字符包含换行符;没有设定s的时候,是不包含换行符的。
/ .*?brown fox.* /s | the quick brown fox jumps over the lazy dog. it's brown fox. |
/ ^.*?brown fox.*$ /m | the quick brown fox jumps over the lazy dog. it's brown fox. |
/ ^.*?brown fox.*$\n.* /m | the quick brown fox jumps over the lazy dog. it's brown fox. |
/ ^.*?brown fox.*$ /ms | the quick brown fox jumps over the lazy dog. it's brown fox. |
x修正符会使模式中的空白字符(被转义的和在字符类[]中的除外)完全被忽略,以及#和下一个换行符之间的所有字符也被忽略—这样就可以加入注释了。
/ .*? brown\sfox .* # sample/x | the quick brown fox jumps over the lazy dog. it's brown fox. |
/ th[e ]e # th e is matched/x | th e quick brown fox jumps over the lazy dog. it's brown fox. |
模式修正符序列通常跟在结束定界符后面,但是也可以放在模式内部,甚至子模式内部。
/ (?x)th[e ]e # th e is matched/ | th e quick brown fox jumps over the lazy dog. it's brown fox. |
(?im) (?im-s) (?ism-s)都是合法的。减号表示取消的意思。
元字符都有哪些?
\ ^ $ . [ ] | ( ) ? * + { }
模式中方括号中间的部分称为字符类,字符类中可用的元字符限于\ ^(排除字符类,仅当其为第一个时有效) -。
注意字符类只匹配目标中的一个字符,或者某个字符不属于字符类定义的字符集。
常见的字符类有 \d \D \s \S \w \W。
子模式是什么?
一个正则表达式可以包含多个子模式,子模式由()定界,可以嵌套。相当于一个小分组。
一是用于选择分支:cat(alina|alog) 将匹配catalina,catalog二者之一。
二是捕获分组:匹配的子模式可以进行逆向引用,按照左括号的顺序决定逆向索引。
/ .*?(quick brown fox).*?(brown fox).*/s | the quick brown fox jumps over the lazy dog. it's brown fox. |
非捕获组:由于逆向引用的数目有限,最大是9,所以要忽略不需捕获的组—在子模式左括号后面加上?:来表示该组无需捕获。如((?:red|bad)(car|bar))。
如果非捕获组中需要模式修正符,可以直接将模式修正符放在?和:之间。如
/(?i:sat|sun)/ 和 /(?:(?i)sat|sun)/是等价的。
/ .*?(quick brown fox).*?(?i:Brown fox).*/s | the quick brown fox jumps over the lazy dog. it's brown fox. |
逆向引用
安全的做法是在相应的左括号之后使用与之相关的逆向引用。逆向引用通常用在替换中。
如/\3,the ((red|white) (king|queue))/对于目标串“king,the red king”应该也是匹配的。但是不保证所有的环境都支持这种写法。
逆向引用的值以最后一次匹配的为准。
/([abc]){3}/匹配“abc”时,\1将是c,而非a。
量词和贪婪模式
量词表示一个模式需要重复匹配的数目,格式{min,max},{min,} ,{,max},{equals}, ?,+,*。
默认情况下,大多数正则表达式工具是按照贪婪原则匹配的—尽可能匹配更多的字符。
如/(\d{1,5})\d/匹配“123456”时,\1的值肯定是12345,而不是1,或者1234之类的。
非贪婪模式ungreedy是指,在满足整个模式匹配的前提下,总是取最小的量词数目结果。在量词后面加上?即可,或者使用U修正符。
如/(\d{1,5}?)\d/匹配“123456”时,\1的值肯定是1,而不是12345。
一次性子模式
正则表达式的匹配过程是这样的:先拿出模式的一个独立单元如.*,然后检查目标字符串,看是否有匹配的,如果匹配,接着贪婪到不能匹配为止;如果遇到不匹配,则对前面已经解析过的模式进行回溯,比如减少一个量词,看剩下的部分能否匹配,重复这个过程直到达到量词的最小要求,如果还不能匹配,则返回无法匹配的结果。
由于回溯的过程比较费时,一次性子模式的目的就是要去掉回溯过程。用(?>)表示。
如/(?>\d)+foo/当遇到不匹配foo的bar时,解析器会立即返回不匹配的结果而不会回溯。
注意一次性子模式属于非捕获子模式,不能被逆向引用。
/(?>\d+)*[!?]/ | aaaaaaaaaaaaa |
当一个没有设定重复上限的子模式中还包含同样没有设定重复上限的子模式时,程序容易花费较长时间。而一次性子模式可以很好的规避这个问题。
断言
断言就是在目标字符串的当前匹配位置进行的一种测试,但是这种测试并不占用目标字符串,也不会移动模式在目标字符串中的当前匹配位置。
常见的断言有^ $ \b \B \A \Z \z \G。注意这些断言不能出现在字符类中。
前向断言—从目标字符串的当前位置向前测试断言条件是否成立。
前向肯定断言(?=)和前向否定断言(?!),括号里的内容是断言。断言的方向是根据断言之外的内容确定的。在断言之前称前向,之后称后向。(臆断勿喷)
如/\w+(?=;)/表示一串文本后面有一个分号,但是分号不在匹配的结果中。
/.*(?=;)/ | the lazy dog; |
/\d{3}(?!0)/ | 5678 |
后向断言用(?<)和(?<!)表示。一般而言,后向断言使用的子模式需要有确定的长度值,否则编译错误。
使用后向断言与一次性子模式结合,可以有效的匹配文本的结束部分。
/(?<!foo)bar/ | foobar goobar |
一个模式中可以包含多个相继的断言,断言也可以嵌套。断言的子模式也是非捕获的。
条件子模式:(?(condition)yespattern|nopattern) condition可以是一个断言,也可是一个捕获组的引用,也可以是R—递归调用。
递归
(?R)表示一个对自己的引用。注意结合一次性子模式,避免无限循环。
测试工具
编写正则表达式的技巧
考虑避免匹配什么,慎用相互嵌套的无限重复量词。