正则表达式学习1
首先说明一下,这篇文章是张子阳老师http://www.cnblogs.com/JimmyZhang/archive/2007/10/24/936151.html写的,只是他为了说明更加清楚及格式排的更加有序,是以pdf文件的形式展现给读者的。在此引用他的这篇文章主要是为了学习。
什么是正则表达式?
正则表达式也叫做匹配模式(Pattern),它由一组具有特定含义的字符串组成,通常用于匹配和替换文本。
匹配单个字符
1.匹配固定单个字符
所有的单个大小写字母、数字及后面讲述的特殊字符,都是一个正则表达式,它们只能匹配单个字符,且这个字符与它本身相同,eg:对于表达式“i”:
Text
Jimmy is a junior developer and jimmy lives in xi’an.
RegEx
i
Result
Jimmy is a junior
需要注意:对于表达式"m”来说,它的匹配是jimmy,请注意这里的匹配方式:并不是一个"m"一次匹配了字符串"mm",而是一个"m"分两次匹配了单个字符"m",不管这两个"m"是紧挨着或者如同上面的"i"那样分散在句子的不同地主。
将多个固定单个字符进行组合就构成了一个匹配固定字符串的表达式。eg:"Jimmy",它也是一个正则表达式,它由多个匹配固定单个字符的表达式组成,它只可以匹配任何与它完全相同的文本:
Text
Jimmy is a junior developer and jimmy lives in xi’an.
RegEx
Jimmy
Result
Jimmy is a junior developer and jimmy lives in xi’an.
你可以将"Jimmy"这个表达式的匹配过程理解成这样:它由"j"、"i"、"m"、"m"、"y"这五个固定的单个字符组成。对于每个单个字符来说,只能匹配与它相同的字符:而将这五个单个字符组合起来的时候,它就匹配 字符排列顺序与表达式完全相同且相应位置上的字符也与对应字符相同 的字符串(实际上也就是与表达式完全相同的字符串)。
由于这种匹配方式的灵活度最小,只能匹配与它完全相同的字符,所以也叫“全字匹配”。
2.匹配任意单个字符
"."可以匹配任意的单个字符、英文字母、数字及它本身。我们现在结合上面介绍的全字匹配来学习它。
Text
regular.doc
regular1.exe
regular2.dat
expression.doc
express.dat
RegEx
regular.
Result
regular.doc
regular1.exe
regular2.dat
expression.doc
express.dat
可以看到,对于表达式"regular."来说,前面"regular"部分是一个全字匹配,只能固定的匹配"regular"字符串;后面的"."部分可以匹配任意单个字符(包含字符"."本身)。
"."可以连续使用,比如我们可以写出".e.."这样的正则表达式。它将匹配所有:前面有任意一个字符,紧跟着一个e,随后又跟着任意两个字符的文本。
Text
regular.doc
regular1.exe
regular2.dat
expression.doc
express.dat
RegEx
.e..
Result
regular.doc
regular1.exe
regular2.dat
expression.doc
express.dat
NOTE:很多情况下,"."不匹配换行。
3.匹配"."元字符
有的时候,我们不想让"."去匹配任何的字符,仅仅想让它匹配"."这一单个字符,也就是仅匹配它本身,此时可以使用"\."来对它进行转义。
Text
regular.exe
regular1.exe
RegEx
r\.
Result
regular.exe
regular1.exe
表达式"r\."仅仅匹配了字符串"r.",没有匹配下面的"r1"。
表达式"r."则会匹配"r1"、"r."及"re"。
NOTE:如果要匹配"\",可以使用"\\"来对它进行转义。后面还会介绍更多需要转义的字符。
4.匹配字符组
4.1字符组的基本语法
"."过于灵活了,它可以匹配几乎所有的单个字符。有的时候,我们只希望匹配有限个字符中的某一个。这个时候,可以使用字符组。
假设有这样一种情况,我们希望验证某个单词是不是拼写错误,比如说"head"是一个单词,"heat"也是一个单词,但"heay"就不是一个单词,所以,"hea"后面要么出现"d",要么出现"t",而如果我们使用"."来进行匹配,那么不管是"heay"也好,"heas"也罢,都会被匹配(被认为是正解的单词)。
正则表达式提供字符组来解决这一问题,对于上例,"hea”后面仅可以匹配"d"或者"t"的情况,它的语法是"[dt]"。中括号是特殊标记,用以划定属于组内的字符的界限,它所代表的含义是:"匹配d或者t"。
Text
bread
heay
teas
head
heat
RegEx
.ea[td]
Result
bread
heay
teas
head
heat
NOTE:字符组虽然由多个字符构成,但它仍只匹配单个字符,而字符组能够匹配的单个字符,即是它定义的字符("[]"内的字符)。"[]"本身不进行字符匹配,它仅仅划定字符组边界。
4.2在字符组中使用字符区间
现在假设我们需要匹配一组文件名,它们的名称为 city0.jpg、city1.jpg...city9.jpg。根据前面介绍的内容,我们很容易写出这样的表达式:"city[0123456789].jpg"。没错!这样写法的确可以达到我们要的效果。如果说写10个阿拉伯数字你觉得并不困难,那么如果要匹配这样的文件名呢?a_1.jpg、b_1.jpg、c_1.jpg...z_1.jpg。这次,你的表达式变成这样了:"[abcdefghijklmnopqrstuvwxyz]_1\.jpg",哇!看着就难受。
正则表达式提供了字符区间来简化这一写法,它的语法是:"起始字符-结束字符"。对于上面匹配阿拉伯数字的例子,它的写法是[0-9]。
NOTE:不一定非要将匹配写成"[0-9]",完全可以根据需要写成"[0-3]",它将仅匹配"0,1,2,3"这个区间。起始字符和结束字符,依据的是它的ASCII值的大小,即是说,将会匹配其ASCII码位于起始字符和结束字符的ASCII之间的所有字符(包含起始、结束字符)。另外,如果起始字符的ASCII值大于结束字符的ASCII值,例如,如果写成"[3-0]",则会出错,导致匹配失败。
Text
city.jpg
city0.jpg
city1.jpg
city2.jpg
city3.jpg
city4.jpg
RegEx
city[1-3]\.jpg
Result
city.jpg
city0.jpg
city1.jpg
city2.jpg
city3.jpg
city4.jpg
NOTE:如果要在字符组("[""]"内)中匹配"-",需要使用转义字符,写法是"\-";而在"[""]"以外,"-"变成了一个普通字符,无需要进行转义。
同样的道理,我们可以写出"[a-z]"来匹配所有的小写字母,"[A-Z]"匹配所有的大写字母,这里就不再举例子了。
现在假设需要在HTML中匹配所有的RGB颜色,我们知道,在Web中,颜色通常表示为诸如"#FF00CC"这样的值,那么结合上面讲述的内容,我们可以像这样使用匹配:
Text
<BODY BGCOLOR="#336633" TEXT="#FFFFFF">
RegEx
#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]
Result
<BODY BGCOLOR="#336633" TEXT="#FFFFFF">
4.3反义字符组
有的时候,我们需要匹配“除了某些字符以外”的字符,这时候,我们可以使用反义字符,其语法是:"[^字符集合]"
我们再以上面的例子为例,现在我们匹配"city1.jpg、city2.jpg、city3.jpg"以外的文件名
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。因为,不管是普通字符组还是反义字符组,它总是确定一定以及肯定要匹配一个字符的。换言之,在本例的模式中,"city"和"."之间是无论如何需要有一个字符的,而"city.jpg"之间没有,所以它不符合此模式。
5.匹配特殊字符
5.1 匹配元字符
我们先对元字符作一个定义:元字符是在正则表达式中具有特殊含义的字符。如我们之前已经介绍过"."就是一个元字符,它用来匹配任意单个字符。当我们要匹配字符"."本身的时候,需要使用"\"来对它进行转义:"\."。
很容易就看出"\"也是一个元字符,它叫做转义字符。所以,当我们需要字符"\"的时候,就需要对它进行转义:"\\"。
回想一下之前讲述的字符组,我们知道"["和"]"也是元字符,当我们需要匹配"["和"]"字符的时候,需要分别写作:"\["和"\]"。
举个例子,假如我们需要匹配"City[0].Name",却写成下面这样:
Text
City[0].Name = "Xian";
City[0]_Name = "Shanghai"
City0.Name = "Hangzhou"
City0_Name = "Beijing"
RegEx
City[0].Name
RegEx
City[0].Name = "Xian";
City[0]_Name = "Shanghai"
City0.Name = "Hangzhou"
City0_Name = "Beijing"
因为没有对"["、"]"和"."进行转义,所以"[0]"被当作字符组来解释,因为字符组中只有一个字符"0",所以,它仅能匹配一个"0",所以"City[0]"相当于City0,又因为没有对"."进行转义,所以它可以匹配它本身以及"_"。
正确的写法:City\[0\]\.Name
Text
City[0].Name = "Xian";
City[0]_Name = "Shanghai"
City0.Name = "Hangzhou"
City0_Name = "Beijing"
RegEx
City\[0\]\.Name
RegEx
City[0].Name = "Xian";
City[0]_Name = "Shanghai"
City0.Name = "Hangzhou"
City0_Name = "Beijing"
5.2 匹配空字符
我想先介绍一下回换行的由来。通常,当我们在键盘上敲击一下回车键时,不管光标此时在哪里,总是会新起一行,然后将无标位于新行的首位置。这在计算机看起来一气呵成,用一个符号来表示就OK了,可在正则表达式中,以及很多语言中,却被表示成了两个动作,一个叫“回车”,一个叫“换行”,在语言,比如VBScript中,就表示成了:Chr(13)&Chr(10)。这与打印机的工作原理有关,大家知道,打印机先于计算机键盘很多年,是键盘的雏形,在打印机上换行时,将进行两个动作:1、将打印头换到下一行;2、将打印头返回到新行的行首位置。也就分别对应了现在的“换行”和“回车”。
在正则表达式中,比较常用的三类空白字符如下表所示:
元字符 | 匹配描述 |
\r | 回车 |
\n | 换行 |
\t | Tab键 |
这种情况使得书写表达式时,变得稍有不便,例如,如果我们想匹配一个换行的效果,我们需要将表达式写成"\r\n"。然后,我们在IE和Firefox中用javascript分别做个测试,却地发现对于IE6(NOTE:IE7我没有试过)来说“\r\n”可以匹配一个换行,而在Firefox中,只用一个“\n”就可以了,使用“\r\n”则无法匹配。
NOTE:不常用的有:\f,换页;\v,垂直Tab。
5.3 匹配特定字符类型
结合“匹配元字符”和“匹配空字符”这两个小节,我们发现这样一个规律:
* 对于"."和"["等来说,它们本身就是元字符,而当给它们前面加上转义字符"\"的时候,它们才代表一个普通字符:"\."匹配字符".","\["匹配字符"["。
* 对于"r"和"n"等来说,它们本身只是普通字符,而只有加上转义字符"\"的时候(变成了"\r"和"\n"),它们代表着元字符:"\r"匹配空字符回车,"\n"匹配空字符换行。
下面将讨论的特定字符类型,就属于上面的第二种情况。
5.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";
5.3.2 匹配字母、数字、下划线
不管是在程序命名中,还是文件命名中,这一类字符集都是最常见的,那就是:所有大小写字母、数字、及下划线,其正则表达式为"[a-zA-Z0-9_]"。
正则表达式中可以使用"\w"来代表这一匹配;类似上一节介绍的,使用"\W"来匹配所有不属于这一字符集的其他字符:"[^a-zA-Z0-9_]"。
元字符 | 匹配描述 |
\w | 所有单个大小字母、数字、下划线,与[a-zA-Z0-9_]相同 |
\W | 所有单个非大小字母、非数字、非下划线,与[^a-zA-Z0-9_]相同 |
Text
abcde
12345
a1b2c
abcd
1234
RegEx
\w\d\w\d\w
Result
abcde
12345
a1b2c
abcd
1234
5.3.3 匹配空字符
最后一种就是匹配空字符了,其语法如下所示:
元字符 | 匹配描述 |
\s | 所有单个空字符,与[\f\n\r\t\v]相同 |
\S | 所有单个非空字符,与[^\f\n\r\v]相同 |