C#基础回顾:正则表达式

??写在前面:本文根据笔者的学习体会结合相关书籍资料对正则表达式的语法和使用(C#)进行基本的介绍。适用于初学者。

??????摘要:正则表达式(Regular Expressions),相信做软件开发的朋友或多或少都对其有所了解,但是你是否可以用其来解决一些问题呢?本文将带着读者从基本的正则语法入手,先向大家展示语法的全貌,然后通过实例演示来对部分语法进行详细介绍。并在结尾给出一些综合性的实例,以便大家参考。

??????索引
????????????1.正则表达式语法概述
????????????2.正则匹配模式
????????????3.Dot Net正则核心对象[部分]
????????????4.部分语法演示
????????????5.综合实例介绍

??????1.正则表达式语法概述(下表摘自网络)
??????下表基本介绍了在进行正则匹配中会用到的一些元字符以及相应的描述。这个可以当作字典来用,并不要求一下子全部记住。元字符:具有特定含义的字符,而不是解释为字符本身的含义,如转义字符‘\‘等。元字符是区分大小写的。


元字符


描述


\


将下一个字符标记为一个特殊字符、或一个原义字符、或一个
向后引用、或一个八进制转义符。例如,‘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>标签内容你会如何操作:

<script>
function?js()
{
???alert(‘恶意代码‘)
}
</script>

????????????因为,[.]不解释换行符,这将使得你需要手动输入换行符来进行匹配。当启用了单行模式后,你就可以简单的一句话搞定:<script>.*?</script>。

????????????2.2 多行模式(Multiline)
????????????同样上表中已经有关于多行模式的解释即:使得"^"和"$"元字符匹配每一行的开头和结尾。相比未采用该模式的时候,这两个字符匹配的则是整个字符串的开头和结尾。

????????????2.3 忽略大小写(IgnoreCase)
????????????这个相信不需要多讲,如果未采用该模式,为了匹配全部所需的结果,可能你要在表达式中罗列所有大小写情况,现在你只需要启用该模式就可以省了很多麻烦。

????????????本节内容可以参考:正则表达式的3种匹配模式

??????3.Dot Net正则核心对象[部分]
??????命名空间:using System.Text.RegularExpressions;

????????????3.1 Regex
????????????该类是Dot Net正则表达式的核心。其中包括了若干静态方法,这使得我们可以不构造Regex对象就可以使用其功能。Regex 类是不可变(只读)的,并且具有固有的线程安全性。可以在任何线程上创建 Regex 对象,并在线程间共享。一般可以利用该类的构造函数来定义所需要的表达式及匹配模式。演示(摘自MSDN):

Regex使用演示
using?System;
using?System.Text.RegularExpressions;

public?class?Test
{
????public?static?void?Main?()
????{
????????//?Define?a?regular?expression?for?repeated?words.
????????Regex?rx?=?new?Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",RegexOptions.Compiled?|?RegexOptions.IgnoreCase);

????????//?Define?a?test?string.????????
????????string?text?=?"The?the?quick?brown?fox??fox?jumped?over?the?lazy?dog?dog.";
????????
????????//?Find?matches.
????????MatchCollection?matches?=?rx.Matches(text);

????????//?Report?the?number?of?matches?found.
????????Console.WriteLine("{0}?matches?found.",?matches.Count);

????????//?Report?on?each?match.
????????foreach?(Match?match?in?matches)
????????{
????????????string?word?=?match.Groups["word"].Value;
????????????int?index?=?match.Index;
????????????Console.WriteLine("{0}?repeated?at?position?{1}",?word,?index);???
????????}???????
????}??
}

?
?

????????????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
继承。)

????????????这里只列出了常用的核心对象,其它对象请大家参考:MSDN

??????4.部分语法演示
????????????4.1 匹配纯文本
????????????这个是最简单的正则匹配,但是实际场景中很少会单独进行纯文本的匹配,一般都会与其它情况相结合。
????????????源文本:This is a test .
????????????表达式:test
????????????匹配结果:This is a test .
????????????C# Code

Regex?r?=?new?Regex("test");//构造表达式
Match?m?=?r.Match("This?is?a?test?.");//匹配源文本
if(m.Success)
{//匹配成功
????Console.WriteLine(m.Value);//获取捕获的字符串
}

?
?

????????????4.2 匹配任意字符
????????????匹配纯文本,并没有显示出正则表达式的魅力,接着来看看如何匹配任意字符。
????????????要点:1)点[.]字符,可以用来匹配任何单个字符,除换行符。只有当选择单行模式的时候,才可以匹配换行符;2)*号用来表示重复多次匹配[会在后面介绍]
????????????源文本:[email protected]#$%^&"‘./,:~!123 sffsf
????????????表达式:.*
????????????匹配结果:[email protected]#$%^&"‘./,:~!123 sffsf
????????????C# Code

Regex?r?=?new?Regex(".*");
Match?m?=?r.Match("[email protected]#$%^&"‘./,:~!123?sffsf");
if(m.Success)
{
????Console.WriteLine(m.Value);
}

?
?

????????????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.7、4.8、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 向前查找
????????????有的时候,我们需要匹配的是某一个字符之前的一段字符串,比如我们需要匹配[email protected]中@前面的一段字符串,该如何呢?
????????????要点:向前查找,实际上就是匹配一个必须匹配但并不返回该结果的匹配方法,使用(?=)来实现。
????????????源文本:[email protected]
????????????表达式:\w+?([email protected])
????????????匹配结果:stg609@163.com
????????????C# Code:类似于4.1的代码,不在缀述。

????????????4.15 向后查找
????????????如果你明白了向前查找,那向后查找就很容易了。区别的只是元字符的不同。
????????????要点:使用(?<=)来实现。
????????????源文本:[email protected]
????????????表达式:(?<[email protected])[\w\.]+
????????????匹配结果:[email protected]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

分组匹配
Regex?r?=?new?Regex(@"(?<Protocol>\w+?)://(?<Address>[\w\.]+)");
Match?m?=?r.Match(@"this?is?a?url?:?http://stg609.cnblogs.com");
if(m.Success)
{
???Consolw.WriteLine(m.Value);//匹配到的内容:http://stg609.cnblogs.com
???foreach(Group?g?in?m.Groups)
???{
??????Console.WriteLine(g.Value);//分别是:http和stg609.cnblogs.com
???}
}

?
?

??????‘@‘;

????????????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-255、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

时间: 2024-11-04 14:29:21

C#基础回顾:正则表达式的相关文章

【Linux系列】【基础版】第四章 Shell基础之正则表达式

4. Shell基础之正则表达式     4.1 正则就是一串有规律的字符串         4.1 grep              4.1.1 格式: grep [-cinrvABC] 'word' filename             4.1.2 -c //count,表示行数             4.1.3 -i //不区分大小写             4.1.4 -n  //显示行号             4.1.5 -r  //遍历所有子目录             4

【DAY26】JAVA 基础回顾

基础回顾 ---------------- 1.跨平台 os JVM : sandbox 1995 2.基本数据类型 byte //1 -128 ~ 127 short //2 -32768 - 32767 int //4 long //8 float //4 doule //8 char //2 boolean //1 3.引用类型 [] class interface 4.运算符 && //短路 || //短路 & // | // ^ //抑或,相同0,不同为1 >>

Linux基础回顾(2)——Linux系统分区二三事

问题来自Linux教材,答案自我整理难免会有不足之处.这是我Linux期末的总结 1. 一块硬盘上可以有几种类型的分区?各自可以有多少个?(各个分区能安装操作系统吗?) 硬盘分区有三种类型的分区:主分区,扩展分区,逻辑分区:一个硬盘最多能划分4个主分区,或者3个主分区加上一个扩展分区,扩展分区上可以划分多个逻辑分区(最多20个).能安装操作系统. 2.用户能否在安装过程中创建扩展分区呢? 分区工具在文件系统类型中没有提供扩展(extended)分区类型,即用户不能根据需要不能手工创建扩展分区.安

PHP移动互联网开发笔记(6)——MySQL数据库基础回顾

最近看了一些架构方面的资料,但是发现基础知识都不怎么牢固,接下来的一段时间,我会定期总结基础知识. 一.数据类型 1.整型 数据类型 存储空间 说明 取值范围 TINYINT 1字节 非常小的整数 带符号值:-128~127 无符号值:0~255 SMALLINT 2字节 较小的整数 带符号值:-32768~32767 无符号值:0~65535 MEDIUMNT 3字节 中等大小的整数 带符号值:-8388608~8388607 无符号值:0~16777215 INT 4字节 标准整数 带符号值

[C#] C# 基础回顾 - 匿名方法

C# 基础回顾 - 匿名方法 目录 简介 匿名方法的参数使用范围 委托示例 简介 在 C# 2.0 之前的版本中,我们创建委托的唯一形式 -- 命名方法. 而 C# 2.0 -- 引进了匿名方法,在 ≥ C# 3.0 的版本中,我们会用 Lambda 表达式进行取代匿名方法,并且用 Lambda 表达式作为编写内联代码的首选方式,因为它更简洁. 匿名方法是,顾名思义,匿名方法就是没有名称的方法.匿名方法最明显的好处就是:可以降低额外另写一个方法的工作量:另外一个好处就是可以直接访问调用者的变量,

四、Android学习第四天——JAVA基础回顾(转)

(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的第四天,在程序中已经遇到了JAVA中以前不常用的一些知识点,赶紧回顾复习一下,打下基础 这里就做个简单的小结: 一.匿名内部类 匿名内部类说白了就是个没有被命名的JAVA类 在以下条件下使用匿名内部类比较适合: ①只用到该类的一个实例时 ②类在定义后被马上用到 ③类非常小(SUN推荐是在4行代码以下

spring 基础回顾 tips01

spring 属性注入时,类中必须有setter 和 getter方法. spring配置文件中: java业务类中注入DAO: private StudentDao studentDao; // 通过属性注入 public StudentDao getStudentDao() { return studentDao; } public void setStudentDao(StudentDao studentDao) { this.studentDao = studentDao; } spri

spring 基础回顾 tips02

spring注入list .set. map. properties 1.list 在xml中这样写: <property name="list"> <list> <value>Michael Huang</value> <ref bean="student"></ref> <value>110</value> </list> </property>

1、java基础回顾与加强

一.    基础回顾 1   集合 1.1  集合的类型与各自的特性 ---|Collection: 单列集合 ---|List: 有存储顺序, 可重复 ---|ArrayList:    数组实现, 查找快, 增删慢 由于是数组实现, 在增和删的时候会牵扯到数组 增容, 以及拷贝元素. 所以慢.数组是可以直接按索引查找, 所以查找时较快 ---|LinkedList:   链表实现, 增删快, 查找慢由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后

基础回顾:get方法和set方法(类的继承多态)

基础回顾:get方法和set方法 定义类成员变量时,可以在@interface中定义,也可以在@implementation中定义: 在@interface中声明,成员变量的状态是受保护的,即“@protected”: 在@implementation中声明,成员变量的状态是私有的,即“@private” 在类的外面,是无法直接访问成员变量的,只有将成员变量修改为@public时,才可以外部访问. 使用@public时,访问成员变量使用“->”,如: time->hour=25; 但使用@pu