注意:很多正则表达式的实现并不一定支持这些这些功能,或是实现的方式有变化
一、重复匹配
1、匹配一个或多个字符
2、匹配零个或多个字符要想匹配同一个字符(或字符集合)的多次重复,只要简单地给这个字符(或字符集合)加上一个 + 字符作为后缀就行了。
匹配一个字符(或字符集合),该字符可以出现零次或多次,只要给这个字符(或字符集合)加上一个 * 字符作为后缀就行了。
3、匹配零个或一个字符
匹配一个字符(或字符集合),该字符可以出现零次或一次,只要给这个字符(或字符集合)加上一个 ? 字符作为后缀就行了。
4、匹配的重复次数
指定字符(或字符集合)的重复次数:[A-Fa-f0-9]{6} 匹配[A-Fa-f0-9]出现6次
为重复匹配次数设定一个区间: [A-Fa-f0-9]{3,6} 匹配[A-Fa-f0-9]出现最少3次,最多6次
[A-Fa-f0-9]{6,} 匹配[A-Fa-f0-9]出现最少6次
5、防止过度匹配
在没有指定重复次数的上限值时,有事可能会导致过度匹配的现象。
如:
原文: <B> tst1 </B> <B> tst2 </B>
正则表达式:<B>.*</B> 匹配结果:<B> tst1 </B> <B> tst2 </B> 过度匹配 ,一个结果
出现这种情况的原因: * 和 + 都是所谓的 “ 贪婪型 ” 元字符,在进行匹配时的行为模式是多多益善,会尽可能从一段文本的开头一直匹配到这段文本的末尾。
正则表达式:<B>.*?</B>
匹配结果:<B> tst1 </B>
<B> tst2 </B> 两个匹配结果
解决办法: 使用懒惰模式,在进行匹配时的行为模式是适可而止,从这段文本的开头匹配碰到第一个匹配时为止。
使用方法: 给贪婪型元字符加上一个 ? 后缀即可
二、位置匹配
1、边界
(1) 单词边界
由限定符\b指定的单词边界
\b 用来匹配一个单词的开始或结尾 \b匹配的是一个位置,这个位置位于一个能够用来构成单词的字符(\w)和一个不能用来构成单词的字符(\W)之间。
例子:
\bcat\b 匹配 cat 单词
\bcat 匹配 cat开头的单词
cat\b 匹配 cat结尾的单词
\B 表明不匹配一个单词边界:即字母数字下划线之间,或者非字母数字下划线之间
(2)字符串边界
^\s*<\?xml.*\?> 匹配xml文件的开头,<?xml version="1.0" encoding="UTF-8"?>
^\s* 解决了<?xml>标签前允许有空格、制表符、换行符等空白字符
</[Hh][Tt][Mm][Ll]>\s*$ 匹配</html>标签 \s*$ 解决</html>标签后面不应该有任何实际内容
$ 匹配输入字符串的结束位置
^ 匹配输入字符串的开始位置
(3)分行匹配模式
(?m)记号就是一个能够改变其他元字符行为的字符串序列。
分行匹配模式:
1、将行分隔符当做一个字符串分隔符来对待
2、 ^ 不仅匹配正常字符串开头,还将匹配行分隔符后面的开始位置
3、 $ 不仅匹配正常字符串结尾,还将匹配行分隔符后面的结束位置
使用时,(?m)必须出现在整个模式的最前面
例子:
(?m)^\s*\/\/.*$ 匹配//开头的行 匹配注释
\/\*(.*\n)*?\*\/ 匹配/**/注释
注意: 很多正则表达式引擎不支持(?m)
三、使用子表达式
1、子表达式
2、子表达式的嵌套子表达式是一个更大的表达式的一部分,把一个表达式划分为一个系列子表达式的目的是为了把哪些子表达式当做一个独立元素来使用。
格式: 子表达式必须用 ( 和 ) 括起来
子表达式允许多重嵌套,这种嵌套的层次在理论上没有限制,但还是应该遵循适可而止的原则。
绝大多数嵌套子表达式没有它们看上去那么复杂。
注意: 把必须匹配的情况考虑周全并写出一个匹配结果符合预期的正则表达式很容易,但把不需要匹配的情况也考虑周全并确保它们被排除在
匹配结果之外往往要困难得多。
在分析各个子表式的时候,应该按照先内后外的原则。
四、回溯引用:前后一致匹配
1、回溯引用匹配
回溯引用允许正则表达式模式引用前面的匹配结果。
回溯引用指的是模式的后半部分引用在前半部分中定义的子表达式。
例子:
正则表达式:\s*(\w+)\s*\1 匹配相邻的两个相同的单词
\1 代表了正则表达式里的第1个子表达式, \2 代表着第2个子表达式,依次类推
2、回溯引用在替换操作中的应用
例子1:
Hello, ben@forta.com is my email adress
正则表达式:(\w+[\w\.]*@[\w\.]+\.\w+)
替换: <A href="mailto:$1">$1</A>
结果:Hello, <A href="mailto:$1">$1</A> is my email adress
$1 为匹配的第一个子表达式的匹配内容
提示: 同一个子表达式可以被引用任意次数—— 只要在需要用到它的地方写出它的回溯引用就行了。
注意: 回溯引用语法在不同的正则表达式实现由很大差异
例子2:
313-555-1234
正则表达式:(\d{3})(-)(\d{3})(-)(\d{4})
替换: ($1)$3-$5
结果:(313)555-1234
提示: 在对文本进行重新排版的时候,把文本分解成多个子表达式的做法往往非常有用,
这可以让我们对文本的排版效果做出更精确的控制。
五、前后查找
1、向前查找和向后查找
例子1:
2、对前后查找取非?= 向前查找指定了一个必须匹配但不在结果中返回的模式<html> this is a test </html>
正则表达式: (?<=<html>).*(?=</html>)
结果: this is a test
一个向前查找模式其实就是一个以 ?= 开头的子表达式,需要匹配的文本跟在 = 的后面
?<= 向后查找指定了一个必须匹配但不在结果中返回的模式
一个向后查找模式其实就是一个以 ?<= 开头的子表达式,需要匹配的文本跟在 = 的后面
注意: 查找中的前、后指模式与被查找文本的相对位置而言,左为前。
负向前查找:将向前查找不与给定模式相匹配的文本。 (?!)
负向后查找:将向后查找不与给定模式相匹配的文本。 (?<!)
例子:
I paid $30 for 100 apples,50 oranges,and 60 pears,I saved $5 on this order。
正则表达式:\\d(?<!$)\\d+\\b
结果:30 100 50 60