写在前面的话:
我是懒人,于是我相信自己是懒人,于是我越来越懒……
虽然正则表达式是个非常历史悠久而且非常通用的东西,但还是有不少童鞋表示这玩艺其实很难懂。
网上资料已然一大堆,但想想为了让自己不再那么懒,那就从正则表达式起,尽力发表一些自己的见解吧。
本系列就命名为《正则表达式是只纸老虎》,由简入难,尽可能介绍到.net 正则表达式的所有语法及用例和一些开发过程中常用的使用场景。
不怎么华丽的分割线
第一关,用来确定一个字符串是否在另一个字符串中出现过。
效果等同于 input.Contains(pattern)
var pattern = "Hello, Regex!";
var sampleRegex = new Regex(pattern);
var input = "This is a sample input: Hello, Regex!";
var isMatch = sampleRegex.IsMatch(input);
Console.WriteLine("isMatch: {0}", isMatch);
第二关,增加大小写选项。也就是说,我们想要匹配的时候,忽略大小写,要怎么办?
效果等同于 input.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) != -1
只需要改造一句,增加一个选项就搞定。
var sampleRegex = new Regex(pattern, RegexOptions.IgnoreCase);
第三关,判断字符串是否以指定字符串开头和结尾。
效果等同于 input.StartsWith(pattern) 和 input.EndsWith(pattern)
var pattern = "^Hello, Regex!"; //使用^来匹配字符串开头
以及
var pattern = "Hello, Regex!$"; //使用$来匹配字符串结尾
举一反三:
那么 ^abc 就是匹配 abc 开头的,abc$ 就是匹配以 abc 结尾的。
^abc$ 那就是匹配字符串为abc的,因为开头结尾都限制了,相当于判断字符串是否直接等于 abc
第四关,判断字符串中是否包含阿拉伯数字。
var pattern = "[0-9]";
既然这里出现了中括号,那么,我就说一下中括号是怎么回事情。
[] 存在两种匹配模式,即[exp]和[^exp],注意这里的"^",可不再是匹配字符串开头的意思,这里是取反的意思。
比如 [0-9] 是匹配 0~9 之间的任意数字,而 [^0-9] 是匹配任何非数字,也就是说,只要出现任何一个不是数字的字符,就能匹配。
var pattern = "[0-9]";
var sample1 = "现在是2014年"; //匹配
var sample2 = "这一句没有数字,哪怕中文的1234567890也不行。"; //不匹配
var pattern = "[^0-9]";
var sample1 = "这一句里出现了一个数字,那就是0。"; //匹配
var sample2 = "0123456789"; //不匹配,因为连一个非数字的字符也没有。
var sample2 = "1234567890"; //匹配,因为全角的4,在这里被认为是非数字(其Unicode码位在0-9之外)。
顺便说一下,这里的减号的用法:
[first-last]
其中 first 是范围的开始字符,last 是范围的结束字符。 字符范围是一系列连续的字符,定义的方法是:指定系列中的第一个字符,连字符 (-),然后指定系列中的最后一个字符。 如果两个字符具有相邻的 Unicode 码位,则这两个字符是连续的。
摘自MDSN:http://msdn.microsoft.com/zh-cn/library/20bw873z(v=vs.100).aspx
第五关,小BOSS,综合应用。匹配以英文字母开头,并且以数字结尾的字符串。
var pattern = "^[a-zA-Z].*[0-9]$";
var regex = new Regex(pattern, RegexOptions.Singleline);
//假假造几个样本来测试一下
var samples = new string[]{
"123456",
"中文开头111",
"abcdefg",
"a1",
"abc222"
};
foreach(var item in samples)
{
Console.WriteLine("input: {0}, isMatch: {1}", item, regex.IsMatch(item));
}
跟我们设想的一样,只有最后两个样本才匹配。
这里用到了几个新的东西,[a-zA-Z],中括里的,是可以组合的,可以单个字符,也可以是一个区间,任意多个组合。
当然如果不嫌麻烦,也可以把 [a-z] 写成 [abcdefghijk......xyz]把26个字母全写上。
同样的,我们随意写一个 [0-35-7a-fA-E],意思是可以匹配 0,1,2,3,5,6,7,a,b,c,d,e,f,A,B,C,D,E 这些字符中的任何一个。
这里用到了 ".*" ,其中句点字符 (.) 匹配除 \n(换行符 \u000A)之外的任何字符,有以下两个限制:
如果通过 RegexOptions.Singleline 选项修改正则表达式模式,或者通过 s 选项修改包含 . 字符类的模式的部分,则 . 可匹配任何字符。
正字符分组或负字符分组中的句点字符将被视为原义句点字符,而非字符类。
也就是说,如果需要用“.”来匹配换行(\n),必须指定 RegexOptions.Singleline 或者使用 s 选项。同时在中括号中的 [.] 并不是匹配任意字符,而仅是匹配句点“.”本身。
其后的星号“*”,表示匹配任意多次(包含0次)。意思就是,除了开头字母,最后一个数字之外,允许中间出现任何多个任意字符。
OK,五关已过,打完收工。