.net中的正则表达式使用高级技巧 (四)

上篇:
.net中的正则表达式使用高级技巧 (一)
.net中的正则表达式使用高级技巧 (二)
.net中的正则表达式使用高级技巧 (三)    

Lazy匹配

语法:??,*?,+?,{n}?,{n,m}?

涵义:简单说,后面的这个?(lazy)告诉正则引擎,它前面的表达式匹配到最短的匹配项就不用匹配下去了,如???本身匹配0-1个匹配项,那么??就取最短的,匹配0个项就不匹配下去了,同理,*?匹配0个,+?匹配1个,{n}?匹配n个,{n,m}?匹配n个。当用@”\w*?”匹配”abcd”时,会有五次成功匹配,每次都匹配的结果都是空字符串为什么会是5次呢,这是因为正则引擎在匹配一个表达式时是一个字符一个字符对比下去的,每成功匹配一次,就前进一下。

判断表达式

语法:

    1A|B,这个是最基本的,A或者B,其实这个不能算判断
    2(?(expression)yes-expression|no-expression),其中no-expression为可选项,意为,如果expression成立,则要求匹配yes-expression,否则要求匹配no-expression
    3(?(group-name)yes-expressioin|no-expression),其中no-expression为可选项,意为,如果名为group-name的组匹配成功,则要求匹配yes-expression,否则要求匹配no-expression
     判断表达式还是很好理解的,唯有一点要注意:@"(?(A)A|B)"不能匹配"AA",为什么呢?要怎么样写才能匹配呢,大家先想想……

我们应该这样写Regex: @”(?(A)AA|B)”,请注意,判断式中的内容并不会做为yes-expressionno-expression表达式的一部分。 

.net 的正则引擎工作特点

    .net的正则引擎工作方式大多数和我们“想当然”的方式一样,只是有几点要注意:
    1.NET Framework 正则表达式引擎尽可能的匹配多的字符(贪婪)。正是由于这一点,所以,不要用@"<.*>(.*)</.*>"这样的正则式来试图找出一个HTML文档中的所有innerText。(我也正是在网上看到有人这样写正则式才决定要写《正则表达式 高级技巧》的,呵呵)
2.NET Framework 正则表达式引擎是回溯的正则表达式匹配器,它并入了传统的非确定性有限自动机 (NFA) 引擎(例如 PerlPython使用的引擎)。这使其有别于更快的、但功能更有限的纯正则表达式确定性有限自动机 (DFA) 引擎。.NET Framework 正则表达式引擎尽量匹配成功,所以,当@"\w+\.(.*)\.\w+"中的.*www. .csdn.net中的.csdn.net都匹配完了,让后面的\.\w+没得字符去匹配时,引擎会进行回溯,以得到成功的匹配。
NET Framework 正则表达式引擎还包括了一组完整的语法,让程序员能够操纵回溯引擎。包括:
“惰性”限定符:??*?+?{n,m}?。这些惰性限定符指示回溯引擎首先搜索最少数目的重复。与之相反,普通的“贪婪的”限定符首先尝试匹配最大数目的重复。
从右到左匹配。这在从右到左而非从左到右搜索的情况下十分有用,或者在从模式的右侧部分开始搜索比从模式的左侧部分开始搜索更为有效的情况下十分有用。
3.NET Framework 正则表达式引擎在(expression1|expression2|expression3)这样情况下,expression1总是最先得到尝试,再依次是expression2expression3           

        public static void Main()
        
{    
            
string s = "THIN is a asp.net developer.";
            Regex reg 
= new Regex(@"(\w{2}|\w{3}|\w{4})",RegexOptions.Compiled|RegexOptions.IgnoreCase);
            MatchCollection mc 
= reg.Matches(s);
            
foreach(Match m in mc)
                Console.WriteLine(m.Value); 
            Console.ReadLine();
    }

输出结果是: TH’ ‘IN’ ‘is’ ‘as’ ‘ne’ ‘de’ ‘ve’ ‘lo’ ‘pe’

附表

转义符

说明

一般字符

.$ ^ { [ ( | ) * + ? \ 外,其他字符与自身匹配。

\a

与响铃(警报)\u0007 匹配。

\b

在正则表达式中,\b 表示单词边界(在 \w \W 之间),不过,在 [] 字符类中,\b 表示退格符。在替换模式中,\b 始终表示退格符。

\t

Tab \u0009 匹配。

\r

与回车符 \u000D 匹配。

\v

与垂直 Tab \u000B 匹配。

\f

与换页符 \u000C 匹配。

\n

与换行符 \u000A 匹配。

\e

Esc \u001B 匹配。

\040

ASCII 字符匹配为八进制数(最多三位);如果没有前导零的数字只有一位数或者与捕获组号相对应,则该数字为后向引用。例如,字符 \040 表示空格。

\x20

使用十六进制表示形式(恰好两位)与 ASCII 字符匹配。

\cC

ASCII 控制字符匹配;例如,\cC Ctrl-C

\u0020

使用十六进制表示形式(恰好四位)与 Unicode 字符匹配。

\

在后面带有不识别为转义符的字符时,与该字符匹配。例如,\* \x2A 相同。

字符类

说明

.

匹配除 \n 以外的任何字符。如果已用 Singleline 选项做过修改,则句点字符可与任何字符匹配。

[ aeiou ]

与指定字符集中包含的任何单个字符匹配。

[^ aeiou ]

与不在指定字符集中的任何单个字符匹配。

[0-9a-fA-F]

使用连字号 (–) 允许指定连续字符范围。

\p{ name }

{name} 指定的命名字符类中的任何字符都匹配。支持的名称为 Unicode 组和块范围。例如,LlNdZIsGreekIsBoxDrawing。可以使用 GetUnicodeCategory 方法找到某个字符所属的 Unicode 类别。

\P{ name }

与在 {name} 中指定的组和块范围不包括的文本匹配。

\w

与任何单词字符匹配。等效于 Unicode 字符类别 [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \w 等效于 [a-zA-Z_0-9]

\W

与任何非单词字符匹配。等效于 Unicode 字符类别 [^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}\p{Lm}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \W 等效于 [^a-zA-Z_0-9]

\s

与任何空白字符匹配。等效于 Unicode 字符类别 [\f\n\r\t\v\x85\p{Z}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \s 等效于 [ \f\n\r\t\v]

\S

与任何非空白字符匹配。等效于 Unicode 字符类别 [^\f\n\r\t\v\x85\p{Z}]。如果用 ECMAScript 选项指定了符合 ECMAScript 的行为,则 \S 等效于 [^ \f\n\r\t\v]

\d

与任何十进制数字匹配。对于 Unicode 类别的 ECMAScript 行为,等效于 \p{Nd},对于非 Unicode 类别的 ECMAScript 行为,等效于 [0-9]

\D

与任何非数字匹配。对于 Unicode 类别的 ECMAScript 行为,等效于 \P{Nd},对于非 Unicode 类别的 ECMAScript 行为,等效于 [^0-9]

断言

说明

^

指定匹配必须出现在字符串的开头或行的开头。。

$

指定匹配必须出现在以下位置:字符串结尾、字符串结尾处的 \n 之前或行的结尾。

\A

指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。

\Z

指定匹配必须出现在字符串的结尾或字符串结尾处的 \n 之前(忽略 Multiline 选项)。

\z

指定匹配必须出现在字符串的结尾(忽略 Multiline 选项)。

\G

指定匹配必须出现在上一个匹配结束的地方。与 Match.NextMatch() 一起使用时,此断言确保所有匹配都是连续的。

\b

指定匹配必须出现在 \w(字母数字)和 \W(非字母数字)字符之间的边界上。匹配必须出现在单词边界上,即出现在由任何非字母数字字符分隔的单词中第一个或最后一个字符上。

\B

指定匹配不得出现在 \b 边界上。

限定符

说明

*

指定零个或更多个匹配;例如 \w* (abc)*。等效于 {0,}

+

指定一个或多个匹配;例如 \w+ (abc)+。等效于 {1,}

?

指定零个或一个匹配;例如 \w? (abc)?。等效于 {0,1}

{ n }

指定恰好 n 个匹配;例如 (pizza){2}

{ n ,}

指定至少 n 个匹配;例如 (abc){2,}

{ n , m }

指定至少 n 个但不多于 m 个匹配。

*?

指定尽可能少地使用重复的第一个匹配(等效于 lazy *)。

+?

指定尽可能少地使用重复但至少使用一次(等效于 lazy +)。

??

指定使用零次重复(如有可能)或一次重复 (lazy ?)

{ n }?

等效于 {n} (lazy {n})

{ n ,}?

指定尽可能少地使用重复但至少使用 n (lazy {n,})

{ n , m }?

指定介于 n 次和 m 次之间、尽可能少地使用重复 (lazy {n,m})

 --完--

 

posted @ 2006-03-03 09:37 Lyn 阅读(6637) 评论(37)  编辑 收藏 所属分类: Regex expression

  回复  引用  查看    
#1楼 2006-03-03 10:30 | birdshome      
Thin兄,讲正则啊,我觉得多举好的例子并仔细分析是比较容易让人理解的方法:)
像“附表”这类东西,大家都有msdn呀 *^_^*
  回复  引用  查看    
#2楼 [楼主]2006-03-03 11:13 | THIN      
@birdshome
呵呵,同意,只是忍不住就Copy了过来凑下门面。
  回复  引用  查看    
#3楼 [楼主]2006-03-03 11:19 | THIN      
@birdshome
难懂的地方我都写了个简单的例子说明,没写例子的地方是我觉得不用例子也清楚才没写的。
  回复  引用  查看    
#4楼 2006-03-03 11:53 | C# hack      
强烈支持!
  回复  引用    
#5楼 2006-03-03 13:13 | windaa [未注册用户]
好文章,慢慢消化,以前看见正则就头痛
  回复  引用    
#6楼 2006-03-03 13:21 | 入门者 [未注册用户]
你好!
验证用","分割的多个邮件地址的正则表达式怎么写?
例如:m1@abc.com,m2@abc.com,m3@abc.com
谢谢

  回复  引用  查看    
#7楼 [楼主]2006-03-03 13:37 | THIN      
string s = "m1@abc.com,m2@abc.com,m3@abc.com";
string[] emails = s.Split(',');
  回复  引用  查看    
#8楼 [楼主]2006-03-03 13:42 | THIN      
一定要用正则的话
string s = "m1@abc.com,m2@abc.com,m3@abc.com";
Regex regEmail = new Regex(@"[\w\.]+@[\w]+\.[\w]+",RegexOptions.IgnoreCase);
MactchCollection mcEmail = regEmail.Matches(s);
foreach(Match m in mcEmail)
Console.Write(m.Value);
  回复  引用    
#9楼 2006-03-03 13:50 | vender [未注册用户]
昨天楼主您提到(?>)还有其他作用,请教我

系列四文,给我隔靴搔痒之感,泛泛而谈,有点像quick tour,冠以“高级技巧”未免有些过,在此推荐一篇更详尽的入门文档,http://perldoc.perl.org/perlretut.html

除了“.net 的正则引擎工作特点”这一节算得上“高级”,其他的仅仅是做了syntax的介绍而以,关于工作特点,《Mastering Regular Expressions》可用了大量的篇幅去说明的,呵呵

  回复  引用    
#10楼 2006-03-03 14:04 | vender [未注册用户]
字里行间透露出的讯息很清楚的说明了作者您自己关于正则式匹配过程的理解是相当深刻的,是按照正则式引擎匹配的工作过程思考的,这种水平是正则式应用的高级阶段(呵呵,不过是实现正则式引擎的初级阶段),是《Mastering Regular Expressions》作者期望读者通过阅读此书达到的理想境界,呵呵。但是您所著四文却不能带给读者更多,实在令人遗憾

冒昧发言,其中不当之处,还望您能海涵
  回复  引用  查看    
#11楼 [楼主]2006-03-03 14:15 | THIN      
@vender
实是水平有限,呵呵,如能补充一些观点,最好不过了

本四文重点不在于深究正则原理,实为给对正则不熟之士预览一下各种正则用法,以便实际使用时有更广的思路,此处之高级也许不是很妥,敢用高级二字,其实是相对于最简单的匹配使用而言。


  回复  引用  查看    
#12楼 [楼主]2006-03-03 14:24 | THIN      
@vender
您提到《Mastering Regular Expressions》一书我没有看过,呵呵,可能以后也不会是去看吧,因为在Regex此一点去看一本书,实在有点花销太大,当然,如果是要研究正则,那另当别论。

  回复  引用    
#13楼 2006-03-03 14:27 | vender [未注册用户]
谦虚谦虚,看得出您自己在这方面还是做了比较深入的研究的,建议不要匆匆结束,如有空可再写一篇,介绍一下《Mastering Regular Expressions》的Chapter 4. The Mechanics of Expression Processing,不过可能一篇介绍不完,我个人觉得此章内容相当引人入胜,对提升正则式应用功力大有裨益

正则式工具在文本分析方面稳坐头把交椅应该是没人会反对了,这个20年前就被广泛(unix平台)使用的优秀工具应该被更多的人掌握
  回复  引用    
#14楼 2006-03-03 14:29 | vender [未注册用户]
原来如此,呵呵,那就算了
  回复  引用  查看    
#15楼 [楼主]2006-03-03 14:39 | THIN      
@vender
既然兄弟对正则了解很深入,又很喜爱这个东西,那何不亲自操刀,写写文章,让我等受教,到时一定认真拜读,我是事务缠身,很多想研究的东西都没有时间去研究(其实广大programmer的情况也估计跟我一样,这也是我写本系列文章的动机所在--快速的掌握一个技术更多的东西),有时这种浅尝Ze止也是让人很痛苦的,呵呵
  回复  引用    
#16楼 2006-03-03 14:54 | vender [未注册用户]
那倒不如直接看书号了,况且我还得练练文笔先,呵呵,就此打住,变闲聊贴了
  回复  引用  查看    
#17楼 2006-03-04 00:36 | birdshome      
blog不就是用来聊天的吗?:)
  回复  引用  查看    
#18楼 2006-03-04 10:32 | Tony Qu      
支持这样的文章,虽然有抄袭之嫌,但可以帮大家省下买书的钱,呵呵
这样的文章也有助于新手学习,应该算是好文吧,以后向楼主学习,多写些这样的文章
  回复  引用    
#19楼 2006-03-04 10:56 | 高级技巧? [未注册用户]
本来就是抄的,而且更谈不上什么高级技巧。
  回复  引用  查看    
#20楼 [楼主]2006-03-04 11:09 | THIN      
@Tony Qu
只是抄了个附表,何来抄袭之嫌?
@高级技巧?
不用把名字换来换去的,启用匿名回复不是给你一再无聊的
  回复  引用    
#21楼 2006-03-07 09:06 | 楼主好样的 [未注册用户]
一人奉献,一些无耻,这都是怎么样的世道?人哦人
  回复  引用  查看    
#22楼 [楼主]2006-03-07 09:37 | THIN      
@楼主好样的
谢谢楼上兄弟,其实网络这东西就是这样,有些人躲在网络背后,无所畏惧的展露自己的阴暗内心,享受意淫后的种种快感。对于这些,看淡些自然就强虏灰飞烟灭了。(其实像我在上面提到的那个人,猜一猜也能猜到是谁,一、他常来园子,二、我在园子里也常回复别人的贴子,但从没人身攻击过别人,和别人有观点冲突的也很少,自己想想就很清楚可能不小心得罪的是谁,只是这种事,真的没必要理会)
对于这种人,我倒是不可惜他们,我可惜的是园子里人多起来后,技术交流的氛围大不如前了,不管是我的贴子,还是别人的,很多人进去一看,并不是静下心来看看人家说的经验技巧,而是先浏览一番,看看是不是从哪抄的,是不是引用了别人的哪些语句,如果有嫌疑,铺天盖地先骂一通。
而且现在都喜那种“指点江湖”的文章,把Java、.net、windows、linux、unix都扯上,再扯上ms、borland等等等等,然后再统观全局,指定江山,何其爽啊,然后进来的一看,略抄一眼原文,要不,找出一处原文中说得不清楚加以补充,要不找出原来中的一处错误强攻,要不再加以主题升华。呵呵,应该都是挺有快感的吧。
--无意愤世忌俗,只是回应各位对本人厚爱的支持者,我将继续做自己想做的,写自己想写的。
  回复  引用  查看    
#23楼 2006-03-23 21:48 | ekeen      
学到一些以前还不了解的东西。

谢谢楼主。
  回复  引用  查看    
#24楼 2006-07-06 18:41 | 思无邪      
很好
  回复  引用    
#25楼 2006-09-14 11:22 | GIS[匿名] [未注册用户]
string s="abcdefghabc";
Regex reg = new Regex(@"ab|ef");
reg.Match(s);
我要达到最先匹配的效果,能否修改上述正则表达式来实现?

对于上述s,也就是说:匹配了ab之后匹配的应该是ef而不是第2个ab.

mhwei000@sina.com
  回复  引用    
#26楼 2006-11-03 17:04 | 旧瓶装新酒[匿名] [未注册用户]
呵呵,得益不少
谢谢楼主。
  回复  引用  查看    
#27楼 2007-03-26 14:03 | 随风随云      
@GIS[匿名]
使用分组
不然(@"ab|ef"); 只是能匹配 ABF或AEF
用这 (?:ab|ef)
  回复  引用  查看    
#28楼 2007-04-29 18:10 | OctoberOne      
原来老师有这么厉害,,,唉!早知道在学校多问问老师啊!可惜没教过我
  回复  引用    
#29楼 2007-08-11 03:28 | 虚拟主机 [未注册用户]
看到这些代码就头痛!!!

虚拟主机.北京虚拟主机.北京虚拟空间.虚拟主机北京.空间租用.主机空间.主机域名.域名注册.注册域名.域名注册北京.企业邮局.企业邮箱.主机托管.主机租用.虚拟空间北京.空间申请.网站推广.百度推广.google推广
  回复  引用    
#30楼 2007-08-21 16:38 | huankfy [未注册用户]
受益了
  回复  引用    
#31楼 2007-08-21 16:40 | huankfy [未注册用户]
以前模模糊糊的认识正则,很少用(主要是不会用,总是写不对正则表达式),看了你的文章算是又长见识了
  回复  引用    
#32楼 2007-08-30 11:30 | 顶 [未注册用户]
爽.~``..爽啊
  回复  引用    
#33楼 2007-10-26 10:34 | sidney_song [未注册用户]
顶一下,确实写的不错.功力深厚,看来是有九阳神功护体呀.^_^
  回复  引用    
#34楼 2007-11-08 11:42 | lanlong [未注册用户]
受益非浅,谢谢!
  回复  引用    
#35楼 2007-12-01 13:55 | 初始小花 [未注册用户]
不错不错,从这四文中补充了一些我的盲点!不过,第三篇中的正负声明那里还是有点模糊。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索

相关文章: