摘要:正则表达式(Regular Expressions),相信作软件开发的朋友或多或少都对其有所了解,可是你是否能够用其来解决一些问题呢?本文将带着读者从基本的正则语法入手,先向你们展现语法的全貌,而后经过实例演示来对部分语法进行详细介绍。并在结尾给出一些综合性的实例,以便你们参考。html
索引:
1.正则表达式语法概述
2.正则匹配模式
3.Dot Net正则核心对象[部分]
4.部分语法演示
5.综合实例介绍正则表达式
1.正则表达式语法概述(下表摘自网络)
下表基本介绍了在进行正则匹配中会用到的一些元字符以及相应的描述。这个能够看成字典来用,并不要求一会儿所有记住。元字符:具备特定含义的字符,而不是解释为字符自己的含义,如转义字符'\'等。元字符是区分大小写的。express
元字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\\' 匹配 "\" 而 "\(" 则匹配 "("。 |
^ | 匹配输入字符串的开始位置。若是设置了正则对象的 Multiline 模式,^ 也匹配 '\n' 或 '\r' 以后的位置。 |
$ | 匹配输入字符串的结束位置。若是设置了正则对象的 Multiline 模式,$ 也匹配 '\n' 或 '\r' 以前的位置。 |
* | 匹配前面的子表达式零次或屡次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或屡次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?" 能够匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配肯定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',可是能匹配 "food" 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的全部 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其余限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽量少的匹配所搜索的字符串,而默认的贪婪模式则尽量多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配全部 'o'。 |
. | 匹配除 "\n" 以外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。当设置了正则对象的Singleline模式,也匹配"\n" |
(表达式) | 匹配 表达式 并获取这一匹配。所获取的匹配能够从产生的 Matches 集合获得,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。 |
(?:表达式) | 匹配 表达式 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供之后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是颇有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。 |
(?=表达式) | 正向预查,在任何匹配 表达式 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不须要获取供之后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配以后当即开始下一次匹配的搜索,而不是从包含预查的字符以后开始。 |
(?!表达式) | 负向预查,在任何不匹配 表达式 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不须要获取供之后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配以后当即开始下一次匹配的搜索,而不是从包含预查的字符以后开始 |
x|y | 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 能够匹配 "plain" 中的 'a'。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 能够匹配 "plain" 中的'p'。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 能够匹配 'a' 到 'z' 范围内的任意小写字母字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 能够匹配任何不在 'a' 到 'z' 范围内的任意字符。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 能够匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。不然,将 c 视为一个原义的 'c' 字符。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
\xn | 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为肯定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可使用 ASCII 编码。. |
\num | 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)\1' 匹配两个连续的相同字符。 |
\n | 标识一个八进制转义值或一个向后引用。若是 \n 以前至少 n 个获取的子表达式,则 n 为向后引用。不然,若是 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
\nm | 标识一个八进制转义值或一个向后引用。若是 \nm 以前至少有 nm 个得到子表达式,则 nm 为向后引用。若是 \nm 以前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。若是前面的条件都不知足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。 |
\nml | 若是 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。 |
\un | 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (©)。 |
2.正则匹配模式
在正则匹配中,通常有三种匹配模式:单行、多行和忽略大小写。除了忽略大小写这个以外,其他2个模式很容易误导使用者(包括我本身在内),初学者会下意识的认为此2者不能共存,其实否则。这2个模式的做用效果并不冲突,使用这2个模式只会改变某几个元字符(或者称关键字)的意义,从而使得匹配的时候产生不一样的效果。
2.1 单行模式(Singleline)
若是观察上表,会发现已经在描述[.]元字符的时候对单行模式的做用进行了解释:使得点[.]能够用来解释换行符。这在多行应用中会有很大的便捷性。试想,原来若是你须要匹配<script></script>标签内容你会如何操做:windows
由于,[.]不解释换行符,这将使得你须要手动输入换行符来进行匹配。当启用了单行模式后,你就能够简单的一句话搞定:<script>.*?</script>。安全
2.2 多行模式(Multiline)
一样上表中已经有关于多行模式的解释即:使得"^"和"$"元字符匹配每一行的开头和结尾。相比未采用该模式的时候,这两个字符匹配的则是整个字符串的开头和结尾。网络
2.3 忽略大小写(IgnoreCase)
这个相信不须要多讲,若是未采用该模式,为了匹配所有所需的结果,可能你要在表达式中罗列全部大小写状况,如今你只须要启用该模式就能够省了不少麻烦。函数
本节内容能够参考:正则表达式的3种匹配模式post
3.Dot Net正则核心对象[部分]
命名空间:using System.Text.RegularExpressions;this
3.1 Regex类
该类是Dot Net正则表达式的核心。其中包括了若干静态方法,这使得咱们能够不构造Regex对象就可使用其功能。Regex 类是不可变(只读)的,而且具备固有的线程安全性。能够在任何线程上建立 Regex 对象,并在线程间共享。通常能够利用该类的构造函数来定义所须要的表达式及匹配模式。演示(摘自MSDN):编码
3.2 Match类
该类用于表示单个正则表达式的匹配。能够经过多种方式来获得该对象:1)利用Regex.Match()方法返回一个Match对象;2)利用Match对象自己的NextMatch()方法来返回一个新的Match对象。
Match对象的主要属性及方法:
属性名称 | 说明 |
---|---|
Captures | 按从里到外、从左到右的顺序获取由捕获组匹配的全部捕获的集合(若是正则表达式用 RegexOptions.RightToLeft 选项修改了,则顺序为按从里到外、从右到左)。该集合能够有零个或更多的项。(从 Group 继承。) |
Empty | 获取空组。全部失败的匹配都返回此空匹配。 |
Groups | 获取由正则表达式匹配的组的集合。 |
Index | 原始字符串中发现捕获的子字符串的第一个字符的位置。(从 Capture 继承。) |
Length | 捕获的子字符串的长度。(从 Capture 继承。) |
Success | 获取一个值,该值指示匹配是否成功。(从 Group 继承。) |
Value | 从输入字符串中获取捕获的子字符串。(从 Capture 继承。) |
方法名称 | 说明 |
---|---|
NextMatch | 从上一个匹配结束的位置(即在上一个匹配字符以后的字符)开始返回一个包含下一个匹配结果的新 Match。 |
Result | 返回已传递的替换模式的扩展。例如,若是替换模式为 $1$2,则 Result 返回 Groups[1].Value 和 Groups[2].Value(在 Visual Basic 中为Groups[1].Value 和 Groups[2].Value)的串联。 |
3.3 Group类
从Match类的主要属性中能够看出有一部分属性是继承自Group类,若是你看了Group类,则会发现Match和Group很相似。
属性名称 | 说明 |
---|---|
Captures | 按从里到外、从左到右的顺序获取由捕获组匹配的全部捕获的集合(若是正则表达式用 RegexOptions.RightToLeft 选项修改了,则顺序为按从里到外、从右到左)。该集合能够有零个或更多的项。 |
Index | 原始字符串中发现捕获的子字符串的第一个字符的位置。(从 Capture 继承。) |
Length | 捕获的子字符串的长度。(从 Capture 继承。) |
Success | 获取一个值,该值指示匹配是否成功。 |
Value | 从输入字符串中获取捕获的子字符串。(从 Capture 继承。) |
4.部分语法演示
4.1 匹配纯文本
这个是最简单的正则匹配,可是实际场景中不多会单独进行纯文本的匹配,通常都会与其它状况相结合。
源文本:This is a test .
表达式:test
匹配结果:This is a test .
C# Code:
4.2 匹配任意字符
匹配纯文本,并无显示出正则表达式的魅力,接着来看看如何匹配任意字符。
要点:1)点[.]字符,能够用来匹配任何单个字符,除换行符。只有当选择单行模式的时候,才能够匹配换行符;2)*号用来表示重复屡次匹配[会在后面介绍]
源文本:afewf@#$%^&"'./,:~!123 sffsf
表达式:.*
匹配结果:afewf@#$%^&"'./,:~!123 sffsf
C# Code:
4.3 匹配特殊字符
若是须要匹配特定的某个字符,该怎么办?若是你还记得4.1的演示,就应该知道能够直接用该字符去匹配。但是,若是要匹配的那个字符是元字符,那这个办法就无效了,由于它被解释为其它含义,而非字符自己。这个时候,须要用到转义字符‘\’。
要点:使用转义字符对元字符进行转义。
源文本:C:\windows
表达式:C:\\windows
匹配结果:C:\windows
C# Code:相似于4.1的代码,不在缀述。
4.4 匹配字符集合
有的时候,咱们要匹配的字符有多种可能的情形,好比大小写不一样的字符或者干脆就是彻底不一样的字符。
要点:使用“[”和“]”元字符来囊括全部可能出现的字符情形。
源文本:1.txt 2.txt 3.txt a1.txt a2.txt 4b.txt 4B.txt
表达式:[123bB]\.txt
匹配结果:1.txt 2.txt 3.txt a1.txt a2.txt 4b.txt 4B.txt
分析:“[”和“]”自己不匹配任何字符,只负责定义一个字符集合。这两个符号之间的全部组成部分都是字符。
技巧:在使用字符集合的时候,可能会常用[0123456789]、[abcdefgh]等等链接的集合,这个时候咱们能够利用一个“-”连字符来简化。如[0-9]、[a-h]等。须要注意的是:1)避免让这个区间的尾字符小于它的首字符,如[z-a];2)“-”连字符只有出如今“[”和“]”之间才被视为元字符,在其它状况下,它只是一个普通的字符。
C# Code:相似于4.1的代码,不在缀述。
4.5 匹配数字
[0-9]能够用来匹配任何一个数字,还能够有更简化的写法"\d"。
源文本:1.txt 2.txt 3.txt
表达式:\d\.txt
匹配结果:1.txt 2.txt 3.txt
C# Code:相似于4.1的代码,不在缀述。
4.6 匹配字母和数字
字母、数字及下划线常常用做文件名的规范,能够用"\w"来匹配这三种情形,相似于[a-zA-Z0-9_]。
源文本:1.txt 2.txt 3.txt a.txt
表达式:\w\.txt
匹配结果:1.txt 2.txt 3.txt a.txt
C# Code:相似于4.1的代码,不在缀述。
4.7 匹配一个或多个字符
4.6 所示的文件名都只有一个字符,可是更多的状况是会出现多个字符如"abc.txt"、 "a2a2.txt"。这种状况就须要咱们匹配多个字符。
要点:想要匹配一个字符的屡次出现。可使用“+”元字符。“+”元字符用来匹配字符的一次或屡次重复。好比能够用a+\.txt来匹配a.txt、aa.txt、aaaaaaa.txt。
源文本:a234_234.txt
表达式:\w+\.txt
匹配结果:a234_234.txt
分析:上述匹配时,\w做为整一个元字符被进行一次或屡次重复。
C# Code:相似于4.1的代码,不在缀述。
4.8 匹配零个或多个字符
与4.7不一样的是能够匹配零个字符。而4.7必需要匹配到一个字符。若是将4.7的表达式改为\w*\.txt,仍能够匹配成功。
要点:匹配零个或多个,可使用“*”元字符。能够利用a*\.txt来匹配.txt、a.txt、aa.txt。
源文本:a234_234.txt、.txt
表达式:\w*\.txt
匹配结果:a234_234.txt、.txt
C# Code:相似于4.1的代码,不在缀述。
4.9 匹配零个或1个字符
要点:“?”元字符,能够用来匹配零个或1个字符。
源文本:a234_234.txt、.txt
表达式:\w?\.txt
匹配结果:a234_234.txt、.txt
C# Code:相似于4.1的代码,不在缀述。
4.10 匹配的重复次数
+、*均可以进行屡次重复匹配,可是没法限制匹配次数,若是只须要匹配有限次数,该怎么办呢?
要点:“{”和“}”之间的数字能够用来限制匹配的最小、最大次数。1){2}表示匹配2次;2){2,}表示至少匹配2次,最多不限;3){2,4}表示至少匹配2次,最多匹配4次。
源文本:a234_234.txt
表达式:\w{2,4}\.txt
匹配结果:a234_234.txt
C# Code:相似于4.1的代码,不在缀述。
4.11 贪婪型匹配与懒惰型匹配
上述4.七、4.八、4.10中的{n, }都属于贪婪型元字符。之因此称之为贪婪型,是因为*、+、{n, }在匹配的时候都是按多匹配、多多益善而不是适可而止。如,使用<title>.*</title>匹配"<title>this is title</title> aaaa </title> ssss",则匹配的结果并非所但愿的<title>this is title</title>而是""<title>this is title</title> aaaa </title>"。那么如何才能让匹配适可而止呢?
要点:在贪婪型匹配元字符后加上“?”元字符,就能够成为懒惰型匹配,进行适可而止的匹配。
源文本:<title>this is title</title> aaaa </title> ssss
表达式:<title>.*?</title>
匹配结果:<title>this is title</title> aaaa </title> ssss
C# Code:相似于4.1的代码,不在缀述。
4.12 子表达式
顾名思义,子表达式天然是整个表达式的一部分。就好像咱们小学数学的算式同样:1+2*(3+4)+3,其中(3+4)就是一个子表达式。能够把子表达式当作是一个小的总体。子表达式,会在许多场合使用到,且容许嵌套。
源文本:abcabcabc.txt
表达式:(abc){3}\.txt
匹配结果:abcabcabc.txt
C# Code:相似于4.1的代码,不在缀述。
4.13 回溯引用匹配
回溯即要先后呼应,好比<H1>test</H1>,开始标签是<H1>,结束标签也要是</H1>。
要点:利用子表达式做为参数,根据子表达式出现的顺序进行相应的查找。
源文本:<H1>this is Test</H1>
表达式:<H([1-6])>.*?</H(\1)>
匹配结果:<H1>this is Test</H1>
分析:([1-6])做为一个子表达式,至关于一个参数。(\1)中的"1"表示第一个子表达式,可是1只是一个普通的字符,所以须要\1对1进行转义,使之表示第一个表达式所匹配到的结果。
C# Code:相似于4.1的代码,不在缀述。
4.14 向前查找
有的时候,咱们须要匹配的是某一个字符以前的一段字符串,好比咱们须要匹配stg609@163.com中@前面的一段字符串,该如何呢?
要点:向前查找,实际上就是匹配一个必须匹配但并不返回该结果的匹配方法,使用(?=)来实现。
源文本:stg609@163.com
表达式:\w+?(?=@)
匹配结果:stg609@163.com
C# Code:相似于4.1的代码,不在缀述。
4.15 向后查找
若是你明白了向前查找,那向后查找就很容易了。区别的只是元字符的不一样。
要点:使用(?<=)来实现。
源文本:stg609@163.com
表达式:(?<=@)[\w\.]+
匹配结果:stg609@163.com
C# Code:相似于4.1的代码,不在缀述。
4.16 单词边界
看过上面几个例子,你是否是以为有什么不妥?是否发现咱们匹配出来的结果有的时候只是某个单词的一部分,我想这应该不是你但愿获得的结果。那么如何来匹配一个完整的单词呢?下面咱们对4.10进行改进
要点:使用\b来匹配一个单词的开始与结束。
源文本:a234_234.txt、234.txt
表达式:\b\w{2,4}\.txt\b
匹配结果:a234_234.txt、234.txt
分析:由于增长了单词边界的限制,因此a234_234.txt就不能获得匹配。
C# Code:相似于4.1的代码,不在缀述。
4.17 分组匹配
一个URL,若是你想同时获取这个URL的协议部分和域名部分,该怎么作呢?
要点:经过(?name)来定义一个分组。
源文本:this is a url : http://stg609.cnblogs.com/
表达式:(?<Protocol>\w+?)://(?<Address>[\w\.]+)
匹配结果:this is a url : http://stg609.cnblogs.com/
分组1名称:Protocol 分组1捕获:http
分组2名称:Address 分组2捕获:stg609.cnblogs.com
分析:(?<Protocol>\w+?)用来捕获http,其中<Protocol>是分组的名称,\w+?则是普通的表达式。
C# Code:
5.综合性实例
如下实例按照每个示例所写的“规则”,进行正则匹配。其中的“规则”不必定严密,只为举例所用,实际应用中,请你们根据具体的“规则”编写正则表达式。
5.1 匹配邮箱地址
邮箱命名规则:1)邮箱用户名可由英文字母、数字、链接符即[减号-]、下划线、点[.]组成,但开头只能用英文字母或数字。
2)必须包含一个"@"
3)在"@"后面的字符串至少包含一个点[.]号
匹配表达式:[\w\d]+[\w._-\d]*@[\w._-\d]+\.[\w._-\d]+
重点分析:[\w\d]+用来匹配开头1个或多个字母、数字;[\w._-\d]*用来匹配0个或多个字母、数字、下划线、链接符、点;@用来匹配'@';
5.2 匹配IP地址
IPv4地址规则:1)每个数字范围为0-255
2) 共有4个数字,每相邻的2个数字之间经过点[.]分隔
匹配表达式:((1\d{2}|25[0-5]|2[0-4]\d|\d{1,2})\.){3}(1\d{2}|25[0-5]|2[0-4]\d|\d{1,2})
重点分析:(1\d{2}|25[0-5]|2[0-4]\d|\d{1,2})利用分支语法提供4种可选的数字即1XX、250-25五、20X-24X、XX;
要点:分支条件根据从左到右的顺序进行匹配,若是已经找到适合的匹配,则再也不进行其它分支的匹配。所以,要把\d{1,2}做为最后一个分支条件,不然可能会丢失对某些3位数的匹配。
5.3 匹配HTML注释
HTML注释规则:注释必须放在<!--和-->标签之间
匹配表达式:<!--.*?-->
5.4 匹配HTML标签对
HTML标签对规则:1)标签必须由'<'和'>'包括
2)结束标签必须由'</'和'>'包括
匹配表达式:<td\s*?.*?>.*?</td>
匹配模式:单行模式、忽略大小写
要点:此表达式中,经过?来限制重复度,防止过分匹配。
5.5 匹配HTML标签对2
标题标签(<H1>-<H6>)规则:开始标签必须与结束标签相同
匹配表达式:<h([1-6])>.*?</h(\1)>
匹配模式:单行模式、忽略大小写
重点分析:([1-6])用来表示一个子表达式(分组);(\1)用来回溯引用整个表达式前半部分中定义的子表达式,\1表示是第一个子表达式,\2表示第二个表达式,依次类推。
要点:使用回溯引用来难保先后一致。
5.6 匹配<Title></Title>标签对之间的内容
匹配表达式:(?<=<Title>).*?(?=</Title>)
匹配模式:单行模式、忽略大小写
重点分析:(?<=<Title>)用来向后匹配<Title>开头的字符串,可是并不消费<Title>自己;(?=</Title>)用来向前匹配</Title>结尾的字条串,可是并不消费</Title>自己;最终返回的匹配结果包含且仅包含该标签对之间的文字;
要点:使用向前?=、向后?<=查找来进行匹配。
参考资料:
1) Ben Forta,《正则表达式必知必会》,[M],2007.
2) 正则表达式的3种匹配模式
3) 正则表达式30分钟入门教程
4) MSDN
源文来自:http://www.cnblogs.com/stg609/archive/2009/06/03/1492709.html