2010学习计划---正则表达式
摘要总结
. 匹配除换行符以外的任意字符
“+”, 来表示匹配一个或多个(换言之,至少一个)字符组成的字符串。
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
\w 所有单个大小写字母、数字、下划线,与 [a-zA-Z0-9_] 相同
\W 所有单个非大小写字母、非数字、非下划线,与 [^a-zA-Z0-9_] 相同
\s 所有单个空字符,与 [\f\n\r\t\v] 相同
\S 所有单个非空字符,与 [^\f\n\r\t\v] 相同
\d 匹配数字
\b 匹配单词的开始或结束
\B 匹配非单词边界
^ 匹配字符串的开始
$ 匹配字符串的结束
\r 回车
\n 换行
\t Tab 键
贪婪匹配 惰性匹配 匹配描述
? ?? 匹配0个或1个
+ +? 匹配1个或多个
* *? 匹配0个或多个
{n} {n}? 匹配n个
{n,m} {n,m}? 匹配n个或m个
{n,} {n,}? 匹配n个或多个
在 .Net 中使用正则表达式进行查找时,给子模式命名的语法是:?<name>,后向引用的语法是:\k<name>。
在 .Net 中使用正则表达式进行替换时,给子模式命名的语法是:?<name>,后向引用的语法是:${name}。
“.”: 可以匹配任意的 单个 字符、英文字母、数字,以及它本身。
“\”: 来实现转义
“[dt]”: 中括号是特殊标记,用以划定属于组内的字符的界限,它所代表的含义是:“匹配d或者t”。
“[1-3]”: “起始字符-结束字符”依据的是它的 ASCⅡ值的大小,即是说,将会匹配其ASCⅡ码位于 起始字符 和 结束字符 的ASCⅡ之间的所有字符(包含起始、结束字符)。
“[^字符集合]”:不属于这个集合中的字符。(不管是 普通字符组 还是 反义字符组,它总是 确定一定以及肯定 要匹配一个字符的)
正则表达式也叫做匹配模式(Pattern),它由一组具有特定含义的字符串组成,通常用于匹配和替换文本。
通常情况下,如果一个文本中出现了多个匹配,正则表达式返回第一个匹配,如果将global设置为 true,则会返回全部匹配;匹配模式是大小写敏感的,如果设置了 ignore case 为true,则将忽略大小写区别。
1.匹配任意单个字符
“.”可以匹配任意的 单个 字符、英文字母、数字,以及它本身。
Text
regular.doc regular1.exe regular2.dat expression.doc
RegEx
regular.
Result
regular.doc regular1.exe regular2.dat expression.doc
2.匹配“.”元字符
我们不想让“.”去匹配任何的字符,仅仅想让它匹配“.”这一单个字符,也就是仅匹配它本身,此时,可以使用“\.”来对它进行转义。
Text
regular.exe regular1.exe
RegEx
r\.
Result
regular.exe regular1.exe
表达式“r\.”仅仅匹配了字符串“r.”,没有匹配下面的 “r1”。
表达式“r.”则会匹配“r1”、“r.”、以及“re”。
NOTE:如果要匹配“\”,可以使用“\\”来对它进行转义。 后面还会介绍更多需要转义的字符。
3.匹配字符组
3.1 字符组的基本语法
“[dt]”。中括号是特殊标记,用以划定属于组内的字符的界限,它所代表的含义是:“匹配d或者t”。
Text
bread heay teas head heat
RegEx
.ea[td]
Result
bread heay teas head heat
3.2 在字符组中使用字符区间
“起始字符-结束字符”依据的是它的 ASCⅡ值的大小,即是说,将会匹配其ASCⅡ码位于 起始字符 和 结束字符 的ASCⅡ之间的所有字符(包含起始、结束字符)。
Text
city.jpg city0.jpg city1.jpg city3.jpg city4.jpg
RegEx
city[1-3]\.jpg
Result
city.jpg city0.jpg city1.jpg city3.jpg city4.jpg
NOTE:如果要在字符组(“[”“]”内)中匹配“-”,需要使用转义符,写法是“\-”; 而在“[”“]”以外,“-”变成了一个普通字符,无需再进行转义。
3.3 反义字符组
其语法是:“[^字符集合]”
Text
city.jpg city0.jpg city1.jpg city2.jpg city3.jpg city4.jpg citys.jpg cityss.jpg
RegEx
city[^1-3]\.jpg
Result
city.jpg city0.jpg city1.jpg city2.jpg city3.jpg city4.jpg citys.jpg cityss.jpg
注意:这里并没有匹配“city.jpg”。因为,不管是 普通字符组 还是 反义字符组,它总是 确定一定以及肯定 要匹配一个字符的
4.匹配特殊字符
4.1匹配元字符
我们先对元字符作一个定义:元字符是在正则表达式中具有特殊含义的字符。
通过转义符来实现元字符作为普通字符来解释。
“\”也是一个元字符,它叫做转义符。所以,当我们需要匹配字符“\”的时候,就需要对它进行转义:“\\”。
常用的元字符
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
4.2 匹配空字符
元字符 匹配描述
\r 回车
\n 换行
\t Tab 键
我们在IE和Firefox中用javascript分别做个测试,却地发现对于IE6(NOTE:IE7我没有试过)来说“\r\n”可以匹配一个换行,而在Firefox中,只用一个“\n”就可以了,使用“\r\n”则无法匹配。
4.3 匹配特定字符类型
对于“.”和“[”等来说,它们本身就是 元字符,而当给它们前面加上转义字符“\”的时候,它们才代表一个普通字符:“\.”匹配字符“.”,“\[”匹配字符“[”。
对于“r”和“n”等来说,它们本身只是 普通字符,而只有当加上转义字符“\”的时候(变成了“\r”和“\n”),它们才代表着元字符:“\r”匹配空字符回车,“\n”匹配空字符换行。
4.3.1匹配数字类型
元字符 匹配描述
\d 所有单个数字,与 [0-9] 相同
\D 所有非数字,与 [^0-9] 相同
Text
City[0].Name = "Xian"; City[1].Name = "Shanghai"; City[a].Name = "Beijing";
RegEx
City\[\d\]\.Name
Result
City[0].Name = "Xian"; City[1].Name = "Shanghai"; City[a].Name = "Beijing";
NOTE:不管Ignore Case 是否设置为 True,在这种情况下,“\d”与“\D”总是区分大小写的,下面将介绍的也是一样。
4.3.2匹配字母、数字、下划线
元字符 匹配描述
\w 所有单个大小写字母、数字、下划线,与 [a-zA-Z0-9_] 相同
\W 所有单个非大小写字母、非数字、非下划线,与 [^a-zA-Z0-9_] 相同
4.3.3匹配空字符
元字符 匹配描述
\s 所有单个空字符,与 [\f\n\r\t\v] 相同
\S 所有单个非空字符,与 [^\f\n\r\t\v] 相同
5.匹配多个字符
5.1.匹配一个或多个
正则表达式中,可以在 单个字符(比如“j”)、字符组(比如“[abcde]”)、特定字符类型(比如“\d”)、单个任意字符(即“.”) 后面加“+”,来表示匹配一个或多个(换言之,至少一个)字符组成的字符串。
Text
jimmy、jjjimmy、simmy、immy、enjoy、enjjoy
RegEx
j+
Result
jimmy、jjjimmy、simmy、immy、enjoy、enjjoy
电子邮件
Text
somebody@domain.net jimmy_dev@163.com jimmy.dev@hotmail.com jimmy_dev@sina.com.cn
RegEx
\w+@\w+\.\w+
Result
somebody@domain.net jimmy_dev@163.com jimmy.dev.design@hotmail.com jimmy_dev@sina.com.cn
得到的结果还少两个,需要将“.”也加入到字符组。
“-”只在字符组“[]”区间内才是一个元字符,在“[]”以外是普通字符。
在此处,“.”在“[]”区间以外才是元字符,用以匹配任意单个字符,而在“[]”区间以内,它就变成了一个普通字符。
所以,“[\w\.]”可以简写成“[\w.]”(写成“[\w\.]也不会出错”)。
Text
somebody@domain.net jimmy_dev@163.com jimmy.dev.design@hotmail.com jimmy_dev@sina.com.cn
RegEx
[\w.]+@[\w.]+\.\w+
Result
somebody@domain.net jimmy_dev@163.com jimmy.dev.design@hotmail.com jimmy_dev@sina.com.cn
这次,可以看到能够正确地匹配多级域名了
元字符 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
5.2匹配零个或一个字符串
正则表达式中,使用“?”来匹配零个或一个字符。其使用方式与“+”和“*”相同。
Text
These flowers are very beautiful, hope you like them.
This flower is so beautiful, seems like smiling to you.
RegEx
flowers?
Result
These flowers are very beautiful, hope you like them.
This flower is so beautiful, seems like smiling to you.
5.3.匹配指定数目字符
正则表达式中,可以在 单个字符(比如“j”)、字符组(比如“[abcde]”)、特定字符类型(比如“\d”)、单个任意字符(即“.”) 后面加“{数字}”,来表示匹配零个或多个字符组成的字符串。
Text
13991381592 is a valid telephone number.
1369188351 is too short.
RegEx
1[35]\d{9}
Result
13991381592 is a valid telephone number.
1369188351 is too short.
5.4匹配区间以内数目的字符
正则表达式中,使用“{最小数目,最大数目}”的语法来实现,它的使用方式与上一节介绍的匹配固定数目字符的语法相同。
Text
0、10、111、001、789、1234 are all matched numbers. 0d、0h、1xx、99. are not matched.
RegEx
\d{1,3}
Result
0、10、111、001、789、1234 are all matched numbers. 0d、0h、1xx、99. are not matched.
NOTE:我们发现了两个问题:
1、我们不希望 “1234” 被匹配,然而,它被分成两部分“123”和“4”进行了匹配,如何不让它被匹配;
2、为什么要被分成123和4,而不是1和234?我们留待后面讨论。
注意两个特例:
最小数目可以是0,所以 “{0,1}”,相当于 “?”。
如果不限制最大数目,可以将最大数目设为空,所以“\d{1,}”相当于“+”;而“{0,}”相当于“*”。
“{”和“}”也是元字符,当我们需要对它们进行匹配的时候,使用“\”进行转义:“\{”和“\}”。
6贪婪匹配和惰性匹配
6.1 贪婪匹配、惰性匹配概述
贪婪匹配(greedy):它会匹配尽可能多的字符。它首先看整个字符串,如果不匹配,对字符串进行收缩;遇到可能匹配的文本,停止收缩,对文本进行扩展,当发现匹配的文本时,它不着急将该匹配保存到匹配集合中,而是对文本继续扩展,直到无法继续匹配 或者 扩展完整个字符串,然后将前面最后一个符合匹配的文本(也是最长的)保存起来到匹配集合中。所以说它是贪婪的。
惰性匹配(lazy):它会匹配尽可能少的字符,它从第一个字符开始找起,一旦符合条件,立刻保存到匹配集合中,然后继续进行查找。所以说它是懒惰的。
Text
Jimmy is a <b>junior</b> developer <b>living</b> in <b>xi'an</c>.
RegEx
<b>.*</b>
Result
Jimmy is a <b>junior</b> developer <b>living</b> in <b>xi'an</c>.
贪婪匹配 惰性匹配 匹配描述
? ?? 匹配0个或1个
+ +? 匹配1个或多个
* *? 匹配0个或多个
{n} {n}? 匹配n个
{n,m} {n,m}? 匹配n个或m个
{n,} {n,}? 匹配n个或多个
Text
Jimmy is a <b>junior</b> developer <b>living</b> in <b>xi'an</c>.
RegEx
<b>.*?</b>
Result
Jimmy is a <b>junior</b> developer <b>living</b> in <b>xi'an</c>.
贪婪匹配和惰性匹配的过程:
6.2 值得注意的两个匹配模式
一个是“{n}”,对于这种形式的匹配,由于它精确地要求匹配n个字符,所以无所谓贪婪还是惰性,尽管“{n}?”也是正确的匹配写法,但它的匹配结果总是与“{n}”相同。
还有一个就是“??”,它看上去比较古怪且不好理解,因为通常我们使用贪婪匹配的时候都是匹配多个,也就是“*”或者“+”之类的匹配,而这里是0个或1个,它的贪婪与惰性匹配又是如何呢?我们还是看范例来说明:
Text
These flowers are for you, my beloved.
RegEx
flowers?
Result
These flowers are for you, my beloved.
在这个匹配中,匹配是这样的:首先需要匹配“flower”字符串,然后,可以有0个或者1个“s”,按上面讲述的,贪婪匹配匹配尽可能多的,所以flowers被匹配了。
再来看看“??”这种匹配。
Text
These flowers are for you, my beloved.
RegEx
flowers??
Result
These flowers are for you, my beloved.
惰性匹配发现“flower”满足匹配0个的条件,于是将它保存到匹配结果集,然后重新进行匹配查找,直到字符串结束。
6.3匹配边界
1.匹配单词边界
正则表达式中,可以在 字符 前加“\b”,来匹配其 后面 的字符位于字符串首位的字符。
NOTE:以后提到 字符,指:单个字符(比如“j”)、字符组(比如“[abcde]”)、特定字符类型(比如“\d”)、转义过的特殊字符“\[” 或者 单个任意字符(即“.”)。
Text
Attention: Zhang is the first name of JimmyZhang.
RegEx
\bz
Result
Attention: Zhang is the first name of JimmyZhang.
说明:“\bz”匹配所有位于字符串首位的“z”,而对位于字符串中间的“z”则不进行匹配(“JimmyZhang”中的“Z”)。
正则表达式中,可以在 字符 后加“\b”,来匹配其 前面 的字符位于字符串末位的字符。
Text
The cat s cattered its food all over the room. The cat scat tered its food all over the room.
RegEx
cat\b
Result
The cat scat tered its food all over the room. The cat scat tered its food all over the room.
显然,为了精确地匹配“cat”,我们需要在前后都加上字符边界,“\bcat\b”。
Text
The cat scat tered its food all over the room. The cat s cattered its food all over the room.
RegEx
\bcat\b
Result
The cat scat tered its food all over the room. The cat s cattered its food all over the room.
2边界及其相对性
边界的定义:通常情况下,以 空格、段落首行、段落末尾、逗号、句号 等符号作为边界,值得注意的是,分隔符“-”也可以作为边界。
Text
The cat s-cat-tered its food all over the room.
RegEx
\bcat\b
Result
The cat s-cat-tered its food all over the room.
边界的相对性
请牢牢记住边界的这个特点:
当你对一个普通字符,比如“s”,设定边界的时候,它的边界是诸如空格、分隔符、逗号、句号等。
当你对一个边界,比如分隔符“-”或者“,”等,设定边界的时候,它的边界是普通字符。
Text
aaaaxaaaa aaa-x-aaa
RegEx
\bx\b
Result
aaaaxaaaa aaa-x-aaa
我们再看另一个例子:
Text
aaaa,aaaa aaa-,-aaa
RegEx
\b,\b
Result
aaaa,aaaa\ aaa-,-aaa
这次我们匹配逗号“,”,而它本身也是一个边界,结果与上面完全相反。可见,对于“,”而言,它的边界是一个普通字母。
边界的相对性是很重要的,因为我们很多时候需要匹配诸如“<”这样的字符。
3。匹配非单词边界 “\B”
Text
The cat scat tered its food all over the room. The cat s cattered its food all over the room.
RegEx
\Bcat
Result
The cat scat tered its food all over the room. The cat s cattered its food all over the room.
说明:它的匹配规则是这样的:字符“c”必须出现,但是不能位于字符串首位;随后跟两个固定字符“a”和“t”。
Text
The cat scat tered its food all over the room. The cat s cattered its food all over the room. The cat scattered its food all over the room.
RegEx
\Bcat\B
Result
The cat scat tered its food all over the room. The cat s cattered its food all over the room. The cat scattered its food all over the room.
说明:首先,必须出现字符“c”,且不能位于字符串首位;接着,“c”后面必须出现字符“a”;最后,必须出现字符“t”,且它不能位于字符串的末尾。
4.匹配文本边界
4.1匹配文本首
在正则表达式中,可以在 匹配模式 的第一个字符前添加 “^”,以匹配 满足模式且位于全部文本之首的字符串。
Text
city.jpg、city1.jpg are all beautiful pictures except city9.jpg city.jpg、city1.jpg are all beautiful pictures except city9.jpg
RegEx
^city\d?\.jpg
Result
city.jpg、city1.jpg are all beautiful pictures except city9.jpg city.jpg、city1.jpg are all beautiful pictures except city9.jpg
按照之前说的,它的匹配过程是这样:
1. 假设匹配模式是 city\d?\.jpg,对文本进行匹配。
2. 一共找到 6 个符合模式的文本:第一行 和 第二行的 city.jpg, city1,jpg 及 city9.jpg
3. 从所有匹配的文本中筛选出位于文本首位的匹配文本:即第一行的 city.jpg,删除所有其他匹配。
如果我们在第一行的city.jpg中添第几个空格,就破坏了这个匹配。
Text
city.jpg、city1.jpg are all beautiful pictures except city9.jpg
RegEx
^city\d?\.jpg
Result
city.jpg、city1.jpg are all beautiful pictures except city9.jpg
可见,没有找到任何匹配,所以,我们进行文本边界匹配时,通常还需要添加对空字符的处理:
Text
city.jpg、city1.jpg are all beautiful pictures except city9.jpg
RegEx
^\s*city\d?\.jpg
Result
city.jpg、city1.jpg are all beautiful pictures except city9.jpg
4.2 匹配文本末
在正则表达式中,可以在 匹配模式 的最后一个字符后添加 “$”,以匹配 满足模式且位于全部文本之末的字符串。
总结 :“\b”和“\B”是对 匹配模式(表达式) 中某个字符出现的进行位置(单词首位还是末位)进行限制。“^”和“$” 是对 整个待搜索文本 的 匹配模式(表达式) 出现位置(文本首位还是文本末位)进行限制。它们的关系是一小一大。
7.匹配子模式
1.子模式
在正则表达式中,可以使用“(”和“)”将模式中的子字符串括起来,以形成一个子模式。将子模式视为一个整体时,那么它就相当于一个单个字符。
Text
This is the first line.<br> This is the second line.<br><br/><br /> This is the third line.<br>>>>>
RegEx
(<br\s*/?>){2,}
Result
This is the first line.<br> This is the second line.<br><br/><br /> This is the third line.<br>>>>>
2.“或”匹配
在正则表达式中,可以使用“|”将一个表达式拆分成两部分“reg1|reg2”,它的意思是:匹配所有符合表达式reg1的文本 或者 符合表达式reg2的文本。
Text
The <b>text of</b> this row is bold. The <i>text of</i> this row is italic.
RegEx
</?i>|</?b>
Result
The <b>text of</b> this row is bold. The <i>text of</i> this row is italic.
3.在子模式中使用“或”匹配
Text
1932 is supposed to be matched as a whole, but it is matched only part of it. 2055 is mathced in the right way. 3019 is out of range, but it's still matched partly.
RegEx
(19|20)\d{2}
Result
1932 is supposed to be matched as a whole, but it is matched only part of it. 2055 is mathced in the right way. 3019 is out of range, but it's still matched partly.
4.嵌套子模式
8.后向引用
正则表达式中,使用“\数字”来进行后向引用,数字表示这里引用的是前面的第几个子模式。
我们回头在看本节第一个例子,我们也可以这样写:
Text
Is the cost of of gasline going up?
RegEx
(of) \1
Result
Is the cost of of gasline going up?
这里,表达式“(of) \1”使用了后向引用,意思是:“\1”代表前面第一个匹配了的子模式的内容,对于本例,因为前面子模式只可能匹配“of”,那么“\1”等价于“of”,整个表达式相当于“of of”。
Text
Is the cost of of gasline going up up? Look up of the TV, your mobile phone is there.
RegEx
(of|up) \1
Result
Is the cost of of gasline going up up? Look up of the TV, your mobile phone is there.
但通常情况下,我们不知道哪些单词重复,这时候,就只能使用后向引用来完成:
Text
Is the cost of of gasline going up up? Look up of the TV, your mobile phone is there. You are the best of the the best.
RegEx
(\w+) \1
Result
Is the cost of of gasline going up up? Look up of the TV, your mobile phone You are the best of the the best.
后向引用的一个常见应用
Text
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
RegEx
<h([1-6])>.*?</h\1>
Result
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
说明:它只匹配了符合HTML语法的文本,对于前后不一致的文本没有进行匹配
.Net中的后向引用
经常写正则表达式的朋友们应该都有体会:对于复杂的匹配,尤其是子模式嵌套子模式的情况,常常判断不清楚后向引用匹配的到底是前面哪个子模式,比如:我们写的“\4”,期望它去匹配第4个子模式,但往往它匹配了第3个或者第5个。
如果能有名字命名子模式就好了,这样,在后向引用中,我们可以使用这个名字,而不用根据数字去判断。
在 .Net 中使用正则表达式进行查找时,给子模式命名的语法是:?<name>,后向引用的语法是:\k<name>。
我们改写前面的范例:
Text
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
RegEx
<h(?<sub>[1-6])>.*?</h\k<sub>>
Result
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
可以看到,我们给子模式([1-6])起了个名字sub,然后在后向引用中使用了它“\k<sub>”,“\k<sub>”就相当于“\1”。
9.文本替换
1.使用后向引用进行文本替换
需要注意的是:大部分语言的正则表达式实现,在查找中,使用后向引用来代表一个子模式,其语法是“\数字”;
而在替换中,其语法是“$数字”。
1.1 高亮显示文本
假设我需要高亮显示所有h1中的文本,我们就可以使用后向引用来完成:
Text
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
RegEx
<h1>(.*?)</h1>
Replace
<h1 style="background:#ff0">$1</h1>
Result
<h1 style="background:#ff0">This is a valid header</h1>
<h2>This is not valid.</h3>
说明:“$1”代表了<h1></h1>之间的文本。
1.2 替换电话号码格式
我们的电话格式通常都是:(区号)电话,比如说:(029)8401132;现在假设我们要求把文本中所有的电话格式都改为:029-8401132,我们可以这样做:
Text
(020)82514769
(021)83281314
(029)88401132
RegEx
\((\d{3})\)(\d{8})
Replace
$1-$2
Result
020-82514769
021-83281314
029-88401132
需要留意的是这里对元字符“(”和“)”进行了转义,并且,在替换结果中,我们要求它不出现。
2.Net 中的文本替换
同后向引用在查找时的情况类似,在 .Net 中,在替换时也可以对后向引用进行命名。
在 .Net 中使用正则表达式进行替换时,给子模式命名的语法是:?<name>,后向引用的语法是:${name}。
我们修改高亮显示h1文本的范例:
Text
<h1>This is a valid header</h1> <h2>This is not valid.</h3>
RegEx
<h1>(?<sub>.*?)</h1>
Replace
<h1 style="background:#ff0">${sub}</h1>
Result
<h1 style="background:#ff0">This is a valid header</h1>
<h2>This is not valid.</h3>
10.预查和非获取匹配
1.非获取匹配
Text
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
RegEx
Windows ([\w.]+\b)
Replace
Win$1
Result
Win1.03 and Win2.0 fisrt Released in 1985 and 1987 respectively.
Win95 and Win98 are the successor.
Then Win2000 and WinXp appeared.
WinVista is the Latest version of the family.
正则表达式中,可以在子模式内部前面加“?:”来表示这个子模式是一个 非获取匹配,非获取匹配不会被保存,不能在后向引用中获取。
Text
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
RegEx
Windows (?:[\w.]+\b)
Page 36 of 42
Replace
Win$1
Result
Win$1 and Win$1 fisrt Released in 1985 and 1987 respectively.
Win$1 and Win$1 are the successor.
Then Win$1 and Win$1 appeared.
Win$1 is the Latest version of the family.
我们看到,由于子模式没有被保存,所以“$1”被当作一个普通字符进行了处理。
而如果我们只是进行查找匹配,不进行替换,那么它们返回的效果相同:
Text
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
RegEx
Windows (?:[\w.]+\b)
Result
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
可见,所谓 非获取匹配,意思就是说它只进行匹配,并不保存结果供以后引用。
2.正向预查
可以使用 正向预查 来解决这个问题。本例中,写法是:“Windows(?= [\d.]+\b)”。
它的语法是在 子模式内部 前面加“?=”,表示的意思是:
首先,要匹配的文本必须满足此子模式 前面 的表达式(本例,“Windows ”);
其次,此子模式不参与匹配。
Text
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
RegEx
Windows( ?=[\d.]+\b)
Result
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
这次,你大概了解了 “非获取匹配” 这五个汉字的含义,它们仅仅起一个限制作用,不参
匹配。你可以将 正向预查 理解成为自定义的边界(\b),这个边界位于 表达式末。
反言之,你可以将位于表达式末的 \b 理解成非获取匹配的一个特例:(?=[ ,.\r\n<>;\-])。
Text
aaaax-aaa aaaaxaaaa
RegEx
x(?=[,.\r\n<>;\-])
Result
aaaax-aaa
aaaaxaaaa
你也可以这样理解上面的匹配过程:
1. 先进行普通匹配:Windows ([\d.]+\b)
2. 然后从匹配文本中将 子模式 内的文本排除掉。
3反向预查
反向预查 的语法是在子模式内部前面加“?<=”,表示的意思是:
首先,要匹配的文本必须满足此子模式 后面 的表达式(本例,“\d+.\d+”);
其次,此子模式不参与匹配。
Text
CNY: 128.04
USD: 22.5
USD: 23.5
HKD: 1533.5
CNY: 23.78
RegEx
(?<=CNY: )\d+\.\d+
Result
CNY: 128.04 USD: 22.5 USD: 23.5 HKD: 1533.5 CNY: 23.78
与前面类似:你可以将 反向预查 理解成为自定义的边界(\b),这个边界位于 表达式首。
反言之,你可以将位于 表达式首 的 \b 理解成一个非获取匹配的一个特例:(?<=[ ,.\r\n<>;\-])。注意,我没有写全所有边界。
Text
aaa-xaaaa
aaaxaaaaa
RegEx
(?<=[,.\r\n<>;\-])x
Result
aaa-xaaaa
aaaxaaaaa
你也可以这样理解上面的匹配过程:
1. 先进行普通匹配:(CNY: )\d+\.\d+
2. 然后从匹配文本中将 子模式 内的文本排除掉。
4.正向、反向预查组合
我们可以将正向预查 和 反向预查 组合起来使用,比如我们想获取所有 head 之间的文本,就可以这么写:
Text
<h1>This is header.</h2>
<h2>This is header,too.</h2>
<span>This is not a header.</span>
RegEx
(?<=<h(?<number>[1-6])>).*?(?=</h\k<number>>)
Result
<h1>This is header.</h2>
<h2>This is header,too.</h2>
<span>This is not a header.</span>
注意,这里我综合应用了前面的知识,将首尾不一致的“<h1></h2>”做了过滤
5.负正向预查、负反向预查
5.1 负正向预查
如同 \b 有与之相对的 \B 一样,正向预查 也有它的 逆过程,称之为 负正向预查。
在正则表达式中,可以在子模式内部前面加 “?!” 来形成一个 负正向预查,它的效果与 “?=” 相反。
Text
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
RegEx
Windows(?! [\d.]+\b)
Result
Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.
Windows 95 and Windows 98 are the successor.
Then Windows 2000 and Windows Xp appeared.
Windows Vista is the Latest version of the family.
从结果我们看到,它匹配了后面不是数字版本的 Windows。
5.2 负反向预查
在正则表达式中,可以在子模式内部前面加 “?<!” 来形成一个 负反向预查,它的效果与“?<=” 相反。
Text
CNY: 128.04
USD: 22.5
USD: 23.5
HKD: 1533.5
Page 41 of 42
CNY: 23.78
RegEx
(?<!CNY: )\b\d+\.\d+
Result
CNY: 128.04
USD: 22.5
USD: 23.5
HKD: 1533.5
CNY: 23.78
这次,它匹配所有前面不是CNY的金额,也就是 HKD 和 USD 后面的数字。