接上篇--.NET高级技术之正则表达式
Posted IT高级程序吸金
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了接上篇--.NET高级技术之正则表达式相关的知识,希望对你有一定的参考价值。
正则表达式
先来看几个需求
看到这样的需求,是不是很无奈?当掌握正则表达式之后,一切变得很简单
1.什么是正则表达式,正则表达式能做什么?
正则表达式是用来进行文本处理的技术,是语言无关的,在几乎所有语言中都有实现。javascript中还会用到。
一个正则表达式就是由普通字符以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
正则表达式可以:
字符串的匹配、字符串的提取、字符串的替换
正则表达式第一步:元字符
. 匹配除
之外的任何单个字符 例如正则表达式“b.g”能匹配如下字符串:“big”、“bug”、“b g”,但是不匹配“buug”,“b..g”可以匹配“buug”。
[ ] 匹配括号中的任何一个字符 例如正则表达式“b[aui]g”匹配bug、big和bag,但是不匹配beg、baug。
可以在括号中使用连字符“-”来指定字符的区间来简化表示,例如正则表达式[0-9]可以匹配任何数字字符,这样正则表达式“a[0-9]c”等价于“a[0123456789]c”就可以匹配“a0c”、“a1c”、“a2c”等字符串;还可以制定多个区间,例如“[A-Za-z]”可以匹配任何大小写字母,“[A-Za-z0-9]”可以匹配任何的大小写字母或者数字。
( ) 将 () 之间括起来的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域;这个元字符在字符串提取的时候非常有用。把一些字符表示为一个整体
有两个作用:1、改变优先级;2、定义提取组两个作用
| :将两个匹配条件进行逻辑“或”运算。'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"
*:匹配0至多个在它之前的子表达式,和通配符*没关系。例如正则表达式“zo*”能匹配 “z” 、“zo”以及 “zoo”;因此“.*”意味着能够匹配任意字符串。
"z(b|c)*"→zb、zbc、zcb、zccc、zbbbccc。"z(ab)*"能匹配z、zab、zabab(用括号改变优先级)。
+ :匹配前面的子表达式一次或多次,和*对比(0到多次)。例如正则表达式9+匹配9、99、999等。“zo+”能匹配 “zo”以及 “zoo” ,不能匹配"z"。
? :匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 。一般用来匹配“可选部分”。
{n} :匹配确定的 n 次。"zo{2}"→zoo。例如,“e{2}” 不能匹配“bed”中的“e”,但是能匹配“seed”中的两个“e”。
{n,} :至少匹配n次。例如,“e{2,}”不能匹配“bed”中的“e”,但能匹配 “seeeeeeeed”中的所有“e”。
{n,m} :最少匹配 n 次且最多匹配 m 次。“e{1,3}”将匹配“seeeeeeeed”中的前三个“e”。
^(shift+6) :匹配一行的开始。例如正则表达式“^regex”能够匹配字符串“regex我会用”的开始,但是不能匹配“我会用regex”。
^另外一种意思:非!
$ :匹配行结束符。例如正则表达式“浮云$” 能够匹配字符串“一切都是浮云”的末尾,但是不能匹配字符串“浮云呀”
注意这些简写表达式是不考虑转义符的,这里的就表示字符,而不是C#字符串级别的,在C#代码中需要使用@或者双重转义。区分C#级别的转移和正则表达式级别的转移,恰好C#的转义符和正则表达式的转义符都是而已。正则表达式的转移是在C#之后的(层层盘剥)。把C#的转义符想成%就明白了。在C#看来@"-"就是-这个普通的字符串,只不过在正则表达式分析引擎看来他有了特殊含义。"\d"或者@"d"
d:代表一个数字,等同于[0-9]
D:代表非数字,等同于[^0-9]
s:代表换行符、Tab制表符等空白字符
S:代表非空白字符
w:匹配字母或数字或下划线或汉字,即能组成单词的字符
W:非w ,等同于[^w]
d:digital;s:space、w:word。大写就是“非”
.Net中的正则表达式
正则表达式在.Net就是用字符串表示,这个字符串格式比较特殊,无论多么特殊,在C#语言看来都是普通的字符串,具体什么含义由Regex类内部进行语法分析。
正则表达式(Regular Expression)的主要类:Regex
常用的3种情况:(C#语法)
1、判断是否匹配:Regex.IsMatch(“字符串”,”正则表达式”)
2、字符串提取:Regex.Match(“字符串”,“要提取的字符串的正则表达式”); 字符串提取(循环提取所有):Regex.Matches()
3、字符串替换:Regex.Replace(“字符串”,”正则”,”替换内容”);
正则表达式是对字符串进行匹配的语法,像name like '%李%'一样,定义了一些特殊的“元字符”,用来判断一个字符串是否满足某个规则。正则表达式非常深,编译器都是基于正则表达式,掌握基本使用即可。
基本元字符
字 符 |
描 述 |
转义字符,将一个具有特殊功能的字符转义为一个普通字符,或反过来 |
|
^ |
匹配输入字符串的开始位置 |
$ |
匹配输入字符串的结束位置 |
* |
匹配前面的零次或多次的子表达式 |
+ |
匹配前面的一次或多次的子表达式 |
? |
匹配前面的零次或一次的子表达式 |
{n} |
n是一个非负整数,匹配前面的n次子表达式 |
{n,} |
n是一个非负整数,至少匹配前面的n次子表达式 |
{n,m} |
m和n均为非负整数,其中n<=m,最少匹配n次且最多匹配m次 |
? |
当该字符紧跟在其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式尽可能少的匹配所搜索的字符串 |
. |
匹配除“ ”之外的任何单个字符 |
(pattern) |
匹配pattern并获取这一匹配 |
(?:pattern) |
匹配pattern但不获取匹配结果 |
(?=pattern) |
正向预查,在任何匹配pattern的字符串开始处匹配查找字符串 |
(?!pattern) |
负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串 |
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 |
匹配非单词边界 |
d |
匹配一个数字字符,等价于[0-9] |
D |
匹配一个非数字字符,等价于[^0-9] |
f |
匹配一个换页符 |
|
匹配一个换行符 |
|
匹配一个回车符 |
s |
匹配任何空白字符,包括空格、制表符、换页符等 |
S |
匹配任何非空白字符 |
|
匹配一个制表符 |
v |
匹配一个垂直制表符。等价于x0b和cK |
w |
匹配包括下划线的任何单词字符。等价于‘'[A-Za-z0-9_]’ |
W |
|
说明:
由于在正则表达式中“ ”、“ ? ”、“ * ”、“ ^ ”、“ $ ”、“ + ”、“(”、“)”、“ | ”、“ { ”、“ [ ”等字符已经具有一定特殊意义,如果需要用它们的原始意义,则应该对它进行转义,例如希 望在字符串中至少有一个“ ”,那么正则表达式应该这么写:\+ 。
使用Regex.IsMatch(被匹配字符串, 正则表达式)判断是否匹配。C#中表示正则表达式最好前面加上@,可以避免转义带来的困扰。
反向引用
反向引用,指把匹配出来的组引用到表达式本身其它地方,比如,在匹配html的标记时,我们匹配出一个<a>,我们要把匹配出来的a引用出来,用来找到</a>,这个时候就要用到反向引用。
语法
a、反向引用编号的组,语法为
umber
b、反向引用命名的组,语法为k<name>
举例
a、匹配成对的HTML标签
@"<(?<tag>[^s>]+)[^>]*>.*</k<tag>>"
b、匹配两个两个重叠出现的字符
public static void Main()
{
string s = "aabbc11asd";
Regex reg = new Regex(@"(w)1");
MatchCollection matches = reg.Matches(s);
foreach(Match m in matches)
Console.WriteLine(m.Value);
Console.ReadLine();
}
返回结果为aa bb 11
辅助匹配组
以下几种组结构,括号中的Pattern都不作为匹配结果的一部分进行保存
1、正声明(?=)
涵义:括号中的模式必须出现在声明右侧,但不作为匹配的一部分
public static void Main()
{
string s = "C#.net,VB.net,php,Java,JScript.net";
Regex reg = new Regex(@"[w#]+(?=.net)",RegexOptions.Compiled);
MatchCollection mc = reg.Matches(s);
foreach(Match m in mc)
Console.WriteLine(m.Value);
Console.ReadLine();
//输出 C# VB JScript
}
可以看到匹配引擎要求匹配.net,但却不把.net放到匹配结果中
2、负声明(?!)
涵义:括号中的模式必须不出现在声明右侧
下例演示如何取得一个<a>标签对中的全部内容,即使其中包含别的HTML tag。
public static void Main()
{
string newsContent = @"url:<a href=""1.html""><img src=""1.gif"">test<span style=""color:red;"">Regex</span></a>.";
Regex regEnd = new Regex(@"<s*a[^>]*>([^<]|<(?!/a))*<s*/as*>",RegexOptions.Multiline);
Console.WriteLine(regEnd.Match(newsContent).Value);
//Result: <a href="1.html"><img src="1.gif">test<span style="color:red;">Regex</span></a>
Console.ReadLine();
}
3、反向正声明(?<=)
涵义:括号中的模式必须出现在声明左侧,但不作为匹配的一部分
4、反向负声明(?<!)
涵义:括号中的模式必须不出现在声明左侧
非回溯匹配
语法:(?>)
涵义:该组匹配后,其匹配的字符不能通过回溯用于后面的表达式的匹配。呵呵,光看这句话肯定搞不懂,我当初为了搞懂这个也花了不少的时间,还是通过实例来说明吧:
"www.csdn.net" 可以通过@"w+.(.*).w+"来匹配,却不能通过@"w+.(?>.*).w+"来匹配!为什么呢?
原因是正则匹配是贪婪的,匹配时它会尽可能多的匹配最多的结果,所以,上例两个正则式中的.*都会把csdn.net匹配完, 这个时候,第一个表达式在开始匹配时发现.w+没得字符给它匹配了,所以它会进行回溯,所谓回溯,就是把.*匹配的结果往回推,回推留出来的字符再用来匹配.w+,直到.w+匹配成功,整个表达式返回成功的匹配结果。而第二个表达式,因使用的是非回溯匹配,所以,.*匹配完后,不允许通过回溯来匹配.w+,所以整个表达式匹配失败。
请注意,回溯匹配是很浪费资源的一种匹配方式,所以,请尽量避免您的正则式要通过回溯来成功匹配,如上例,可以换成@"w+.([^.]+.)+w+"+"。
以上是关于接上篇--.NET高级技术之正则表达式的主要内容,如果未能解决你的问题,请参考以下文章