前段时间我利用业余时间开发了一套基于标签的CMS系统,在其中为了处理基于标签的数据提取与数据填充大量的使用了正则表达式,在这里将我将正则表达式的语法和用法进行简单的描述,然后下篇中将介绍在c#中利用正则表达式的方法与代码实例。
什么是正则表达式
基本说来,正则表达式是一种用来描述一定数量文本的模式。Regex代表Regular Express。我们使用一种自定义的模式来匹配一定数量的文本,并从中提取所需数据。如同window的通配符,如:*.txt查找所有txt文件。*就被解释成任意字符。
一个简单的正则表达式
作为惯例,我们都是从hello world开始的。那么这里同样这样开始。为了匹配hello world这11个字符,正则表达式为:^hello\sworld$。其中^代表开头的锚点、$代表结束的锚点、\s代表匹配一个空格。一个重要的注意事项,正则表达式是占位的,也就是说,正则表达式中的一个字符一定要对应实际文本中的一个字符。如上面的正则表达式就不能匹配” hello world”,因为” hello….”前面多了一个空格。
另一个正则表达式
如果我们需要匹配一个ipv4的ip地址;总所周知,ip地址分为4段,每段以’.’分割。每段大小在0-255之间。其中前三段都以’.’结尾,最后一段没有。经过分析得到如下结论。
1) 前三段的匹配模式是相同的,最后一段的匹配模式与前三段只是不以’.’结尾
2) Ipv4的ip地址每段范围在0-255之间。可以是0-9,可以是10-99,也可以是100-255。其中需要主要的是100-199范围和200-255范围,如果首位以1开头,则后两位可以是任意数字,如果首位以2开头,第二位只能是0-5,而且,当第二位是0-4的时候第三位可以是任意数字,当第二位是5的时候第三位只能是0-5
下面我们写出符合上面第二点的匹配模式
① 当首位是2,且第二位是0-4的时候:2[0-4]\d,
② 当首位是2,且第二位是5的时候:25[0-5]
③ 当首位是0或则1的时候,第二三位可以是任意数字:[01]\d\d
④ 当首位不是0-2的时候,这时该地址就不能是100-255的范围,只能是0-9或者10-99的范围,当在0-9范围的时候,一位任意数字就可以:\d,当在10-99的时候,两位数字就可以:\d{2};
⑤ 然后观察第③和第④点可以发现,当首位是0-1而且出现三位的时候应用第③点,当首位不是0-1且不是三位时应有第④点。变可以融合第③④点为:[01]?\d\d?
现在每段0-255范围的匹配模式已经书写完成了,然后考虑前三段以’.’结尾的问题,最终获得匹配模式: ^(2[0-4]\d|25[0-5]|[01]?\d\d?\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$
元字符
通过以上的两个实例,相信大家已经对正则表达式有了一个初步的理解,现在这里列出正则表达式的元字符,元字符的定义和语言的关键字含义类似,都是一些在系统中有特殊含义的字符。
1) ‘.’ :匹配任意字符
2) \w :匹配字母或数字或下划线或汉字
3) \s :匹配空白字符
4) \d :匹配任意数字
5) \b :匹配开头或则结尾
6) ^ :匹配字符串的开头
7) $ :匹配字符串的结尾
重复与贪婪重复和惰性重复
重复的含义是指重复匹配满足某一匹配模式的文本。如例中(匹配ip)的’?’号就是一个重复的例子,它的含义是某一匹配模式,至多出现一次。以下列出一些重复的标示:
1) * :星号,重复任意多次,如:\w*,代表任意字母,数字,下划线,汉字出现任意多次
2) + :加号:至少出现一次,如:\d+,代表任意数字至少出现一次
3) ? :问好:至多出现一次(出现一次或则不出现),如:\s?,代表空白字符出现0或则1次
4) {n}:n代表任意数字,如:.{5},代表任意字符出现5次
5) {n,}:n代表任意数字,如:\d{5,},代表任意数字出现5到多次
6) {n,m}:n,m代表任意数字,如:\d{5,10},代表任意数字出现5到10次
贪婪与惰性匹配
首先看一个正则表达式例子:“<.*>”
这个正则表达式将匹配以’<’开头,’>’结尾中间任意次任意字符,如:<br/>,<div/>,</script>等。当如果用该正则表达式去匹配<div>hello world</div>的话被匹配出的文本就是<div>hello world</div>,因为默认情况下正则表达式是贪婪匹配。正则表达式引擎或默认情况下将默认搜索最后一个匹配锚点。所以本例中的最后匹配锚点是</div>的>而不是<div>的>。这便是贪婪匹配。
既然明白有贪婪匹配,就必然需知惰性匹配
以上为上面这个正则表达式例子稍作改动:<.*?>,我们在*后面加上一个问号便告诉引擎按照惰性匹配的方式进行搜索,使用这个正则表达式匹配<div>hello world</div>得到的结果会有两个,一个是<div>另一个是</div>。因为我们没有限定开头和结尾。
字符集,分歧,反义
字符集:[A-Za-z0-9],匹配一个字符,这个字符是A-Za-z0-9中的任意一个
分歧:(a|b)*,a或则b出现任意多次
反义:[^ab]+,非a和b出现至少一次
分组
正则表达式的分组以()小括号进行标示,如:(\w*)。标示将\w*划分为一个匹配单元,及分组。<(\w+?)[A-Za-z0-9"=\s]*>.*?</\1>这个正则表达式能够匹配如:<div class=”box”>hello world</div>段,值得注意的是我们将\w+进行了分组,然后再后面使用\1引用本分组。默认情况下,引擎将至左向右将第一个分组命名为第1组,第二个分组命名为第2组......我们也能显示的给分组命名,本实例中正则表达式也能写成:<(?<g1>\w+?)[A-Za-z0-9"=\s]*>.*?</\k<g1>>我们将\w+的分组命名为g1,以后通过\k<name>引用。
OK,这次就谈到这里,下篇将阐述在C#语言环境下如何通过正则表达式提取数据,编码用户输入数据,验证用户输入等。