正则表达式必知必会

匹配单个字符

匹配纯文本

正则:Ben
>
Hello, my name is Ben. Please visit my website at http://www.forta.com/.

匹配任意字符

. 匹配任意单个字符。在绝大多数的正则表达式实现里,. 只能匹配除换行符以外的任何单个字符。
正则:sales.
>
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls

匹配特殊字符

元字符是一些在正则表达式里有着特殊含义的字符。如英语句号(.)是一个元字符,它可以用来匹配任何一个单个字符。因为元字符在正则表达式里有着特殊的含义,所以这些字符就无法用来代表它们本身。比如你不能使用 . 类匹配 . 本身。
在元字符的前面加上一个反斜杠就可以对它进行转移,转义序列 . 将匹配 . 本身。
正则:.a.\.xls

>
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls

匹配一组字符

匹配多个字符中的某一个

可以使用元字符 [ 和 ] 来定义一个字符集合,在使用 [ 和 ] 定义的字符集合里,这两个元字符之间的所有字符都是该集合的组成部分,字符集合的匹配结果是能够与该集合里的任意一个成员想匹配的文本。
正则:[ns]a.\.xls
>
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
ca1.xls

利用字符集合区间

模式 [0-9] 的功能与 [0123456789] 完全等价。

正则:[ns]a[0-9]\.xls
>
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
na1.xls
na2.xls
sa1.xls
ca1.xls

其他常用的字符区间:
A-Z:匹配从 A 到 Z 的所有大写字母。
a-z:匹配从 a 到 z 的所有小写字母。

取非匹配

用元字符 ^ 来表明你相对一个字符集合进行取非匹配,也就是除了那个字符集里的字符,其他字符都可以匹配。
正则:[ns]a[^0-9]\.xls
>
sales1.xls
orders3.xls
sales2.xls
sales3.xls
apac1.xls
europe2.xls
sam.xls
na1.xls
na2.xls
sa1.xls
ca1.xls

匹配特定的字符类型

元字符 说明
\d 任何一个数字字符(等价于[0-9])
\D 任何一个非数字字符(等价于[^0-9])
\w 任何一个字母数字字符(大小写均可)或下划线字符(等价于[a-zA-Z0-9_])
\W 任何一个非字母数字或非下划线字符(等价于[^a-zA-Z0-9_])

正则:myArray\[\d\]
>
var myArray = new Array();

if (myArray[0] == 0) {

}

正则:\w\d\w\d\w\d
>
11213
A1C2E3
48075
48237
M1B4F2
90046
H1H2H2

匹配空白字符

元字符 说明
[\b] 回退(并删除)一个字符(Backspace键)
\f 换页符
\n 换行符
\r 回车符
\t 制表符
\v 垂直制表符
\s 任何一个空白字符(等价于[\f\n\r\t\v])
\S 任何一个非空白字符(等价于[^\f\n\r\t\v])

重复匹配

匹配一个或多个字符

  • 匹配一个或多个字符(至少一个;不匹配零个字符的情况)。
    正则:\w+@\w+\.\w+
    >
    Send personal email to ben@forta.com. For questions about a book use support@forta.com. Feel free to send unsolicited email to spam@forta.com (wouldn’t it be nice if it were that simple, huh?).

匹配零个或多个字符

  • 元字符匹配零个或多个字符。
    正则:\w+[\w.]*@[\w.]+\.\w+
    >
    Hello, .ben@forta.com is my email address.

匹配零个或一个字符

? 只能匹配一个字符(或字符集合)的零次或一次出现,最多不超过一次。
正则:https?://[\w./]+
>
The URL is http://www.forta.com/, to connect securely use https://www.forta.com/ instead.

匹配的重复次数

{3}意味着模式里的前一个字符(或字符集合)必须在原始文本里连续重复出现 3 次才算是一个匹配。
{2, 4} 的含义是最少重复 2 次、最多重复 4 次。
{3,} 表示至少重复 3 次。

懒惰型元字符

正则:<[Bb]>.*</[Bb]>
>
This offer is not available to customers living in <B>AK</B> and <B>HI</B>.

因为 * 和 + 都是所谓的“贪婪型”元字符,它们在进行匹配时的行为模式是多多益善而不是适可而止的,会尽可能地从一段文本的开头一直匹配到这段文本的末尾。
在不需要这种“贪婪行为”的时候该怎么办?答案是使用这些元字符的“懒惰型”版本。懒惰型元字符只要给贪婪性元字符加上一个 ? 后缀即可。

贪婪型元字符 懒惰型元字符
* *?
+ +?
{n, } {n, }?

正则:<[Bb]>.*?</[Bb]>
>
This offer is not available to customers living in <B>AK</B> and <B>HI</B>.

位置匹配

单词边界

\b 用来匹配一个单词的开始或结尾。
简单地说,\b 匹配的是一个这样的位置,这个位置位于一个能够用户构成单词的字符(字母、数字和下划线,也就是与 \w 相匹配的字符)和一个不能用来构成单词的字符(也就是与 \W 相匹配的字符)之间。
正则:\bcat\b
>
The cat scattered his food all over the room.

字符串边界

^ 用来定义字符串开头,\$ 用来定义字符串结尾。
注意:不同语言对 ^ \$ 的处理有所不同。比如 Javascript 是按照以上定义实现的,而 Ruby 中 ^ 匹配一行的开始,\$ 匹配一行的结束。具体可参考 http://www.regular-expressions.info/anchors.html。

使用子表达式

子表达式是一个更大的表达式的一部分,把一个表达式划分为一系列子表达式的目的是为了把那些子表达式当做一个独立元素来使用。子表达式必须用 ( 和 ) 括起来。
正则:(19|20)\d{2}
>
ID: 042
SEX: M
DOB: 1967-08-17
Status: Active

| 字符表示或操作符,19|20 将匹配数字序列 19 或 20。

回溯引用:前后一致匹配

正则:[ ]+(\w+)[ ]+\1
>
This is a block of of text, several words here are are repeated, and and they should not be.

\1 不是一个回溯引用,而它引用的正是前面划分出来的那个子表达式。当 (\w+) 匹配到单词 of 的时候,\1 也匹配单词 of;当 (\w+) 匹配到单词 and 的时候,\1 也匹配单词 and。
为了方便理解,可以把回溯引用想象成变量。

前后查找

前后查找包含的匹配本身并不返回,而是用于确定正确的匹配位置,它并不是匹配结果的一部分。

向前查找

从语法上看,一个向前查找模式其实就是一个以 ?= 开头的子表达式,需要匹配的文本跟在 = 后面。

正则:.+(?=:)
>
http://www.forta.com/
https://mail.forta.com/
ftp://ftp.forta.com/

与子表达的对比。
正则:.+(:)
>
http://www.forta.com/
https://mail.forta.com/
ftp://ftp.forta.com/

向后查找

向后查找,以 ?<= 开头的子表达式。
正则: (?=\$)[0-9.]+
>
ABC01: $23.45
Total items found: 4

对前后查找取非

负向前查找讲向前查找不与给定模式相匹配的文本,负向后查找将向后查找不与给定模式相匹配的文本。

操作符 说明 示例
(?=) 正向前查找 \d+(?= dollars) matches 100 in “100 dollars”
(?!) 负向前查找 d+(?! dollars) matches 100 if it is NOT followed by the word “dollars”
(?<=) 正向后查找 (?<=lucky )\d matches 7 in “lucky 7”
(?<!) 负向后查找 (?<!furious )\d matches 7 in “lucky 7”

嵌入条件

(?(backreference)true-regex):? 表示这是一个条件,括号里的 backreference 是一个回溯引用, backreference 存在时会执行true-regex。
(?(backreference)true-regex|false-regex): backreference 不存在时会执行 false-regex。

回溯引用条件

正则:(\()?\d{3}(?(1)\)|-)\d{3}-\d{4}
>
123-456-7890
(123)456-7890
(123)-456-7890
(123-456-7890
1234567890
123 456 7890

(()? 匹配一个可选的左括号,(?(1))|-) 将根据条件是否满足而去匹配 ) 或者 -。如果 (1) 存在,) 必须被匹配,否则 - 必须被匹配。

前后查找条件

前后查找条件的语法与回溯引用条件的语法大同小异,只需把回溯引用替换为一个完整的前后查找表达式就行了。
正则:\d{5}(?(?=-)-\d{4})
>
11111
22222
33333-
44444-4444

(?(?=-)-\d{4}) 使用了 ?=- 来匹配(但不消费)一个连字符,如果条件得到满足(那个连字符存在),-\d{4} 将匹配那个连字符和随后的 4 位数字。