30分钟正则表达式指导
很早就看过这篇文章了,很精典。 你是否曾经想过正则表达式是什么,怎样能够快速得到对它的一个基本的认识?我的目的就是在30分钟内带你入门并且对正则表达式有一个基本的理解。事实是正则表达式并没有它看起来那么复杂。学习它最好的办法就是开始写正则表达式并且不断实践。在最初的30分钟之后,你就应该知道一些基本的结构并且有能力在你的程序或者web页面中设计和使用正则表达式了。对那些想要深入研究的人,现在已经有很多非常好的可用资源来让你更深入的学习。 到底什么是正则表达式? 我相信你对模式匹配的“计算机通配符”字符应该比较熟悉了。例如,如果你想要在一个Windows文件夹中找到所有MircosoftWord文件,你要搜索“*.doc”,因为你知道星号会被解释为一个通配符,它匹配所有序列的字符串。正则表达式就是这种功能的一个更加细节的扩展。 在写处理文本的程序或者web页面时,定位匹配复杂模式的字符串是很常见的。正则表达式就是用来描述这类模式的。这样,一个正则表达式就是一个模式的缩减代码。例如,模式“w+”是表达“匹配任何包含字母数字字符的非空字符串”的精确方法。.NET框架提供了一个功能强大类库,它使得在你的应用程序中包含正则表达式更加容易。使用这个库,你可以轻易地搜索和替换文本,解码复杂的标题,解析语言,或者验证文本。 学习正则表达式的神秘的语法的一个好办法是用例子作为开始学习的对象,然后实践创建自己的正则表达式。 让我们开始吧!
搜索Elvis 假设你要花费你所有的空余时间来扫描文档来寻找Elvis仍然活着的证据。你可以使用下面的正则表达式来搜索: 1.elvis--Findelvis 2.belvisb--Findelvisasawholeword 假设你想要找到所有这样的行,在其中单词“elvis”后面都跟着单词“alive”。句点或者点“.”是一个特殊代码匹配除了换行符之外的任何字符。星号“*”表示重复前面的部分有必要的次数以保证能够有一个匹配。这样,“.*”表示“匹配除了换行符之外的任意数目的字符”。现在建立一个表示“搜索在同一行内后面跟着单词‘alive’的单词‘elvis’”的表达式就是一件简单的事了。 3.belvisb.*baliveb--Findtextwith"elvis"followedby"alive" 让我们看看另一个例子。 确定电话号码的合法性 假设你的web页面收集顾客的7位电话号码,而且你希望验证输入的电话号码是正确的格式,“xxx-xxxx”,这里每个“x”是一个数字。下面的表达式将搜索整个文本寻找这样的一个字符串: 4.bddd-dddd--Findseven-digitphonenumber 5.bd{3}-d{4}--Findseven-digitphonenumberabetterway
.NET正则表达式的基础 让我们探索一下.NET中正则表达式的基础 特殊字符 你应该知道几个有特殊意义的字符。你已经见过了“b”,“.”,“*”,和“d”。要匹配任何空白字符,像空格,制表符和换行符,使用“s”。相似地,“w”匹配任何字母数字字符。 让我们尝试更多的例子: 6.baw*b--Findwordsthatstartwiththelettera 7.d+--Findrepeatedstringsofdigits 8.bw{6}b--Findsixletterwords
表1正则表达式的常用特殊字符 开始阶段 特殊字符“^”和“$”被用来搜索那些必须以一些文本开头和(或)以一些文本结尾的文本。特别是在验证输入时特别有用,在这些验证中,输入的整个文本必须要匹配一个模式。例如,要验证一个7位电话号码,你可能要用: 9.^d{3}-d{4}$--Validateaseven-digitphonenumber 换码字符 当你想要匹配这些特殊字符中的一个时会产生一个错误,像“^”或者“$”。使用反斜线符号来去掉它们的特殊意义。这样,“^”,“.”,和“”,分别匹配文本字符“^”,“.”,和“”。 重复 你已经见过了“{3}”和“*”可以指定一个单独字符的重复次数。稍后,你会看到相同的语法怎样用来重复整个子表达式。此外还有其他几种方法来指定一个重复,如下表所示:
表2常用量词 让我们试试几个例子: 10.bw{5,6}b--Findallfiveandsixletterwords 11.bd{3}sd{3}-d{4}--Findtendigitphonenumbers 12.d{3}-d{2}-d{4}--Socialsecuritynumber 13.^w*--Thefirstwordinthelineorinthetext 在设置和不设置“Multiline”选项的时试试最后一个例子,它改变了“^”的含义。 字符集合 搜索字母数字字符,数字,和空白字符是容易的,但如果你需要搜索一个字符集合中的任意字符时怎么办?这可以通过在方括号中列出想要的字符来轻松的解决。这样,“[aeiou]”就能匹配任意韵母,而“[.?!]”就匹配句子末尾的标点。在这个例子中,注意“.”和“?”在方括号中都失去了他们的特殊意义而被解释为文本含义。我们也可以指定一个范围的字符,所以“[a-z0-9]”表示“匹配任何小写字母或者任何数字”。 让我们试试一个搜索电话号码的更加复杂的表达式: 14.(?d{3}[)]s?d{3}[-]d{4}Atendigitphonenumber 这个表达式将会搜索几种格式的电话号码,像“(800)325-3535”或者“6505551212”。“(?”搜索0个或1个左圆括号,“[)]”搜索一个右圆括号或者一个空格。“s?”搜索0个或一个空白字符。不幸的是,它也会找到像“650)555-1212”这样括号没有去掉的情况。在下面,你会看到怎样用可选项解决这个问题。 否定 有些时候我们需要搜索一个字符,它不是一个很容易定义的字符集合的成员。下面的表格说明了这种字符怎样指定:
表3怎样指定你不想要东西 15.S+--Allstringsthatdonotcontainwhitespacecharacters 后面,我们会看到怎样使用“lookahead”和“lookbehind”来搜索缺少更加复杂的模式的情况。 可选项 要从几个可选项中选择,允许符合任何一个的匹配,使用竖杠“|”来分隔可选项。例如,邮政编码有两种,一个是5位的,另一个是9位的加一个连字符。我们可以使用下面的表达式找到任何一种: 16.bd{5}-d{4}b|bd{5}b--FiveandninedigitZipCodes 当使用可选项时,顺序是很重要的因为匹配算法将试图先匹配最左面的选择。如果这个例子中的顺序颠倒过来,表达式将只能找到5位的邮政编码,而不会找到9位的。我们可以使用可选项来改进十位电话号码的表达式,允许包含区码无论是通过空白字符还是连字符划分的: 17.((d{3})|d{3})s?d{3}[-]d{4}--Tendigitphonenumbers,abetterway
分组 圆括号可以用来划分一个子表达式来允许重复或者其他特殊的处理,例如: 18.(d{1,3}.){3}d{1,3}--AsimpleIPaddressfinder 表达式的第一部分搜索后面跟着一个“.”的一个一位到三位的数字。这被放在圆括号中并且通过使用修饰符“{3}”被重复三次,后面跟着与之前一样的表达式而不带后缀部分。 不幸的是,这个例子允许IP地址中被分隔的部分是任意的一位,两位,或三位数字,尽管一个合法的IP地址不能有大于255的数字。要是能够算术比较一个获取的数字N使N<256就好了,但是只用正则表达式是不能够办到的。下一个例子使用模式匹配测试了基于第一位数字的多种可选项来保证限制数字的取值范围。这表明一个表达式会变得很笨重,尽管搜索模式的描述是简单的。 19.((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?)--IPfinder 一个“回引”用来搜索前面被一个分组捕获的已匹配文本的再现。例如,“1”表示“匹配分组1中已捕获到的文本”。下面是一个例子: 20.b(w+)bs*1b--Findrepeatedwords 它的运行过程是先捕获一个分组1中“(w+)”表示的至少包含一个字母数字字符的字符串,但仅当它是一个单词的开始或结束字符时才行。然后它搜索任意数量的空白字符“s*”后跟以被捕获的文本“1”结尾的单词。 在上面的例子中,想要替换分组“(w+)”这种写法,我们可以把它写成“(?<Word>w+)”来给这个分组命名为“Word”。一个对这个分组的回引可以写成“k<Word>”。试试下面的例子: 21.b(?<Word>w+)bs*k<Word>b--Capturerepeatedwordinanamedgroup 通过使用圆括号,有很多可用的特殊用途的语法元素。一些最常用的归纳如下面这张表格:
表4常用分组结构 前两个我们已经说过了。第三个“(?:exp)”不会改变匹配行为,它只是不像前两个那样捕获已命名的或者计数的分组。 确定察看(PositiveLookaround) 下面四个是所谓的前向或后向断言。它们从当前的匹配向前或向后寻找需要的东西而不在匹配中包含它们。这些表达式匹配一个类似于“^”或“b”的位置而不匹配任何文本,理解这个是很重要的。由于这个原因,他们也被称为“零宽度断言”。最好用例子来解释它们: “(?=exp)”是“零宽度确定前向断言”。它匹配一个文本中在给定后缀之前的位置,但不在匹配中包含这个后缀: 22.bw+(?=ingb)--Thebeginningofwordsendingwith"ing" “(?<=exp)”是“零宽度确定后向断言”。它匹配在给定前缀后面的位置,但不在匹配中包含这个前缀: 23.(?<=bre)w+b--Theendofwordsstartingwith"re" 下面这个例子可以用来重复向三位数为一组的数字中插入逗号的例子: 24.(?<=d)d{3}b--Threedigitsattheendofaword,precededbyadigit 下面是一个同时搜索前缀和后缀的例子: 25.(?<=s)w+(?=s)--Alphanumericstringsboundedbywhitespace 否定察看(NegativeLookaround) 之前,我说明了怎样搜索一个不是特定字符或一个字符集合的成员的字符。那么如果我们想要简单的验证一个字符没有出现,但是不想匹配任何东西怎么办?例如,如果我们想要搜索其中“q”不是后跟着“u”的单词怎么办?我们可以尝试: 26.bw*q[^u]w*b--Wordswith"q"followedbyNOT"u" 运行例子你就会看到如果“q”是一个单词的最后一个字母就不会匹配,比如“Iraq”。这是因为“[^q]”总是匹配一个字符。如果“q”是单词的最后一个字符,它会匹配后面跟着的空白字符,所以这个例子中表达式结束时匹配两个完整的单词。否定察看可以解决这个问题,因为它匹配一个位置而不消耗任何文本。与确定察看一样,它也可以用来匹配一个任意复杂的子表达式的位置,而不仅仅是一个字符。我们现在可以做得更好: 27.bw*q(?!u)w*b--Searchforwordswith"q"notfollowedby"u" 我们使用“零宽度否定前向断言”,“(?!exp)”,只有当后缀“exp”没有出现时它才成功。下面是另一个例子: 28.d{3}(?!d)--Threedigitsnotfollowedbyanotherdigit 相似地,我们可以使用“(?<!exp)”,“零宽度否定后向断言”,来搜索文本中的一个位置,这里前缀“exp”没有出现: 29.(?<![a-z])w{7}--Stringsof7alphanumericsnotprecededbyaletterorspace 这里是另一个使用后向的例子: 30.(?<=<(w+)>).*(?=</1>)--TextbetweenHTMLtags 这个使用后向搜索一个HTML标记,而使用前向搜索对应的结束标记,这样,就能获得中间的文本而不包括两个标记。 评论 标点的另一个用法是使用“(?#comment)”语法包含评论。一个更好的办法是设置“IgnorePatternWhitespace”选项,它允许空白字符插入表达式然后当使用表达式时忽略它。设置了这个选项之后,任何文本每行末尾在数字符号“#”后面的东西都被忽略。例如,我们可以格式化先前的例子如下: 31.TextbetweenHTMLtags,withcomments (?<=#Searchforaprefix,butexcludeit .*#Matchanytext (?=#Searchforasuffix,butexcludeit
贪婪与懒惰 当一个正则表达式有一个可以接受一个重复次数范围的量词(像“.*”),正常的行为是匹配尽可能多的字符。考虑下面的正则表达式: 32.a.*b--Thelongeststringstartingwithaandendingwithb 如果这被用来搜索字符串“aabab”,它会匹配整个字符串“aabab”。这被称为“贪婪”匹配。有些时候,我们更喜欢“懒惰”匹配,其中一个匹配使用发现的最小数目的重复。表2中所有的量词可以增加一个问号“?”来转换到“懒惰”量词。这样,“*?”的意思就是“匹配任何数目的匹配,但是使用达到一个成功匹配的最小数目的重复”。现在让我们试试懒惰版本的例子(32): 33.a.*?b--Theshorteststringstartingwithaandendingwithb 如果我们把这个应用到相同的字符串“aabab”,它会先匹配“aab”然后匹配“ab”。
表5懒惰量词 我已经描述了很多元素,使用它们来开始创建正则表达式;但是我还遗漏了一些东西,它们在下面的表中归纳出来。这些中的很多都在项目文件中使用额外的例子说明了。例子编号在这个表的左列中列出。
表6我们遗漏的东西。左端的列显示了项目文件中说明这个结构的例子的序号 结论 我们已经给出了很多例子来说明.NET正则表达式的关键特性,强调使用工具(如Expresso)来测试,实践,然后是用例子来学习。如果你想要深入的研究,网上也有很多在线资源会帮助你更深入的学习。你可以从访问Ultrapico网站开始。如果你想读一本相关书籍,我建议JeffreyFriedl写的最新版的《MasteringRegularExpressions》。 CodeProject中还有很多不错的文章,其中包含下面的教程: ·AnIntroductiontoRegularExpressionsbyUweKeim ·MicrosoftVisualC#.NETDeveloper'sCookbook:ChapteronStringsandRegularExpressions (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |