路旁的IC卡电话

周五下班回来的路上,”颤抖”的骑着驴,天越来越冷,天黑的也越来越早了,回来的路上的路灯也不亮,摸黑的躲避着一个又一个坑坑洼洼.

走到半路的时候,看到路旁有IC卡电话,突然特别想拿IC卡给锌打个电话,下了车子,好久没有打IC卡电话了,以前没有手机,只有BB机,每天都会盼着BB机响,然后屁颠屁颠的去找IC卡电话回,打电话时候不喜欢有第二个人在,就像在家的时候也是,只要爸妈在家,我打电话接电话都会不自在,慌乱的应付几句就挂掉了.要是爸妈不在家,我就开始把电话弄疯了.呵呵.几年后再回到IC卡电话旁边去打电话时候,心里的感觉和以前即相同又不同.一个人在电话前打电话又兴奋,又狂野.毫无忌惮,随意飘荡.现在有了手机,有了电话,没了传呼机,街道少了IC卡电话,少了那份单纯白痴的感觉.IC卡电话放在车站旁,离路边那么近,声音又小,按键又不灵.不知道网通和电信怎么想的,要放弃这块肉了?给移动联通了?心里很多感概,没写这之前,以为会有很多写的,结果现在一点词儿都没有.唉.那种单纯和可乐无法表达和鱼跃.

周六出去转了半天,穿少了,又遇到下雨,冻坏我了.郁闷.怎么这么冷了.现在不穿外套出门好像差了点.给摔坏的眼镜换了眼镜片,那两个玻璃片儿怎么那么贵呢.改行去卖眼镜好了.^_^.

买了一个CPU风扇,回来换上之后就悔了,我机器声音大竟然和CPU没多大关系,竟然是那块破显卡风扇,唉.而且这个CPU风扇估计也买的贵了点.唉.没钱拉.穷拉.

公司那么吵着要断网络,不能上Q了,不能上MSN了,不能上用DM了.唉.没必要这样吧.那个P2P终结者真是可恶,1M带宽每人给分配5K,你晕不?尝试了几个方法都没有成功跳出限制.无语了.开始实行OA,OA上也要手工点击链接做考勤,上午用了点时间写了一个小工具,取允许范围内的随机时间进行自动考勤.嘿嘿.OAAutoTools.这事啊,不能让地球人知道….嘿嘿.

又阴天,又没睡,算了.不洗衣服了.睡觉.困了.困了.ZZZZzzz~~~~

基于BS支持下的Vrml真实水的实现.

以前写Vrml封包都是嵌入的Blx控件,因为Blx控件没有Logo水印,比较好办.只是本身的效果和多边形等支持上都不是很理想.昨天同事要一个Exe封包封一下场景文件给别人演示一下现在的效果,我就尝试了一下嵌入BS控件封装.本来以为很容易.后来才发现BS很BT,不知道是不是它们做了特别的限制.
嵌入窗口中,测试运行程序马上就自己结束.编译成Exe后就正常,也就是说无法一边调试一边查看,只能编一些,编译成Exe看一下.估计买了Sdk会有这方面的禁止程序结束的方法吧.
独立编译后到没有装过Bs的机器测试,提示缺少控件.我晕.难道还要附属的Dll?查了半天,发现Bs的ocx必须还要附带d3dx9_26.dll,j2k-codec.dll才能支持.晕.
不缺少控件后又出现一个新的问题,就是首次运行竟然提示是否接受授权条款.Regsvr32也会出现这个提示.只在未装过Bs控件的机器上首次提示一次.点”是”后就不会再提示了.回家就开始跟踪注册表,先用SSM跟踪软件动作,结果竟然没提示操作注册表了.架虚拟PC,反复的做注册表镜像,最终才搞定.如下写注册表即可避免授权提示.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINESOFTWAREClassesCLSID{4B6E3013-6E45-11D0-9309-0020AFE05CC8}InprocServer32]
@="BS控件的所在路径"

昨晚又3点多才去睡的,往一个Vrml场景中添加水效果来着.结果照预先看到的范例效果差了一点.不过比原来简单的半透Gif做的水效果强多了.支持物体的反射折射.抓几张图来,图的效果不好.实时浏览的效果会比静止的图片更真实一点.有点小Bug,场景过大时候,晃动视角,会感觉水在”荡漾”,这个不知道如何X掉.

栽树对于在栽草来说还是一件比较幸福的事情.

今天耗费了半天时间进行栽草,因Vrml浏览引擎问题,对面数和其他上面优化的不太好.
从Max随机布置球体取坐标点到写小工具随机旋转缩放生成Use的Lod树.

结果失败了.太消耗了.每秒1祯,没法玩啊.唉.怀念一下,这么多球体,随机的.不容易啊.555~~在Max8中视图已经接近卡死了,尝试用Max9试试,感觉依旧.唉.面和体太多了吧.睡觉去.缺觉!

依旧没有锌的消息,她去哪里了呢?

随机植物处理工具 V2.0

又凌晨3点多了,要去睡觉了,明天还要上班呢.

随机植物处理工具写完了,还算可以吧.

用了点正则表达式.有点晕.

我已经几天没有联系到锌了.很挂念她.希望她能知道我担心挂念,尽快给我打个电话告诉我一下.

今天花了2个多小时时间学会了BS支持的Vrml真实水实现方法,参考的是M17的范例.谢谢M17.

睡觉去了.晚安~~~又是新的一天.

Max9终于拉下来了.哈哈

前些天就看到有人放出Max9下载,结果仔细一看其他人的回复得知其压缩包是损坏的.昨天同事告诉一个网址,当时也没多想,就开驴开始下载,结果把上次明知道是损害的压缩包重新下载了一次,白期待了.700多M呢,唉.

不甘心,就到网上继续搜索.反复确认后开始下载一个比较完整的版本,包括64位和32位.机器转了一夜.全部下载完毕,刚刚安装完毕,呆啊.64位机器安装64位版本竟然说我CPU不支持,郁闷.只好用32位了.View的速度效率果然提高好多好多.帅!

可惜的是Max9不支持以前的任何插件.就连BS的输出Vrml插件都不支持,郁闷.不过还好.我自己的可爱的Maxtools可以正常使用.哈哈

满大街跑的都是月薪上万的小程序员儿!

我转贴的,转贴的,原作者信息我找不到.我只是想自己什么时候能到月薪1W啊.

  我住在海淀区,这里满大街跑的是月薪上万的小程序员儿,还有痛骂计算机专业无美女的项目经理,他们大脑袋、厚眼镜、因熬夜而布满血丝的眼睛,因不见阳光而酷似吸血鬼的脸,穿一个星期不洗的T-SHIRT,很有很有味道的,他们供楼不供车,他们翻开报纸只盯住北边的楼盘,倒不是因为关心奥运村,实在是想离公司近一些。我,衷心地喜欢着这个区。  

有女友去国贸那边应聘工作回来,一脸幸福状地向我描述,地铁站里全是帅哥,地面上更是临风玉树站成了森林,让她的小心灵经受了一次美的洗礼,她晕乎乎地回来了,对那些西装革履、散发名贵男用香水味道、气宇轩昂的白领男人们再三再四地概叹:“F4那算个啥,肚里没货,只知卖相,看看人家,啊,那才叫自信来源于知识,气质来源于财富……” 我打断她语无伦次的胡说八道,问她工作有戏没戏,她说,“凭我的英语水平,能没戏吗?!”

继续阅读

正则表达式简介

有些新手对正则表达式不是很熟悉,有必要在此作一简单回顾。如果你是正则表达式高手,可以不用看这一部分。
正则表达式是描述字符串集的字符串。例如,正则表达式“Mic*”描述所有包含“Mic”,后跟零个或多个字符的字符串。Mickey、Microsoft、Michelangelo 或 Mic 本身都是例子。句号“.”匹配任何字符,“+”类似“*”,但至少要一个字符,所以“Mic+”匹配前述所有除“Mic”以外的串。[a-z]指一个匹配范围,所以[a-zA-Z_0-9]匹配字母、数字或下划线。Regex 称之为单词字符,可以将它写成“w”。所以“w+”匹配至少有一个字符的单词字符序列——换句话说,叫 C 符号(C tokens)。那么这样一来,几乎所有的C 符号都不能以数字开头,因此,下面这个正则表达式是正确的:“^[a-zA-Z_]w*$”。专用字符“^”意思是“以…开始”(除非它位于某个范围之内,这时它的意思是“非”),“$”意思是“结尾”,那么“^[a-zA-Z_]w*$”意思就是:以字母或下划线开始的字母、数字或下划线字符串。
正则表达式在对输入进行有效性验证时非常有用。d 匹配数字,{n}匹配重复n次,于是 ^5d{15}$ 匹配5开头的16位数字,也即是说 MasterCard 信用卡号码。那 ^[45]d{15}$ 就是Visa 卡号,它以4开头。你可以用大括弧对表达式进行分组,下面是个测试。这个表达式描述的是什么呢?^d{5}(-d{4}){0,1}$

提示:{0,1} 意思是重复0次或1次(可以缩写成问号 ?)。想出来了吗?该表达式意思是:五个数字后重复0次或1次(破折号后跟四个数字)。它匹配 02142和98007-4235,但不匹配 3245 或 2345-98761。这也就是美国的邮政编码。大括弧将 ZIP+4 部分分组,所以{0,1}修饰符将应用于整个分组。
以上我仅浅尝即止地说明了正则表达式能做什么。我还没提到替换,由于我没有具体资料,所以不敢描述在 Unicode 中会怎么样。但你能感觉到正则表达式有多么强大。多年来它们乃 UNIX 的中流砥柱,并且在Web 编程和 Perl 这样的语言中更臻完善,其对 HTML 的操作几乎完全是对文本的处理。正则表达式在 Windows 中一直没有得到充分使用,直到 .NET 框架面世,它才正式成为 Windows 家族的一员。

深入浅出之正则表达式(二)

前言:
本文是前一片文章《深入浅出之正则表达式(一)》的续篇,在本文中讲述了正则表达式中的组与向后引用,先前向后查看,条件测试,单词边界,选择符等表达式及例子,并分析了正则引擎在执行匹配时的内部机理。
本文是Jan Goyvaerts为RegexBuddy写的教程的译文,版权归原作者所有,欢迎转载。但是为了尊重原作者和译者的劳动,请注明出处!谢谢!


9.      单词边界

 

元字符<<\b>>也是一种对位置进行匹配的“锚”。这种匹配是0长度匹配。

有4种位置被认为是“单词边界”:

1)        在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)

2)        在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)

3)        在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后

4)        在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面

“单词字符”是可以用“\w”匹配的字符,“非单词字符”是可以用“\W”匹配的字符。在大多数的正则表达式实现中,“单词字符”通常包括<<[a-zA-Z0-9_]>>。

例如:<<\b4\b>>能够匹配单个的4而不是一个更大数的一部分。这个正则表达式不会匹配“44”中的4。

换种说法,几乎可以说<<\b>>匹配一个“字母数字序列”的开始和结束的位置。

 

“单词边界”的取反集为<<\B>>,他要匹配的位置是两个“单词字符”之间或者两个“非单词字符”之间的位置。

 

  • 深入正则表达式引擎内部

让我们看看把正则表达式<<\bis\b>>应用到字符串“This island is beautiful”。引擎先处理符号<<\b>>。因为\b是0长度 ,所以第一个字符T前面的位置会被考察。因为T是一个“单词字符”,而它前面的字符是一个空字符(void),所以\b匹配了单词边界。接着<<i>>和第一个字符“T”匹配失败。匹配过程继续进行,直到第五个空格符,和第四个字符“s”之间又匹配了<<\b>>。然而空格符和<<i>>不匹配。继续向后,到了第六个字符“i”,和第五个空格字符之间匹配了<<\b>>,然后<<is>>和第六、第七个字符都匹配了。然而第八个字符和第二个“单词边界”不匹配,所以匹配又失败了。到了第13个字符i,因为和前面一个空格符形成“单词边界”,同时<<is>>和“is”匹配。引擎接着尝试匹配第二个<<\b>>。因为第15个空格符和“s”形成单词边界,所以匹配成功。引擎“急着”返回成功匹配的结果。

 

  1. 选择符

正则表达式中“|”表示选择。你可以用选择符匹配多个可能的正则表达式中的一个。

如果你想搜索文字“cat”或“dog”,你可以用<<cat|dog>>。如果你想有更多的选择,你只要扩展列表<<cat|dog|mouse|fish>>。

选择符在正则表达式中具有最低的优先级,也就是说,它告诉引擎要么匹配选择符左边的所有表达式,要么匹配右边的所有表达式。你也可以用圆括号来限制选择符的作用范围。如<<\b(cat|dog)\b>>,这样告诉正则引擎把(cat|dog)当成一个正则表达式单位来处理。

  • 注意正则引擎的“急于表功”性

正则引擎是急切的,当它找到一个有效的匹配时,它会停止搜索。因此在一定条件下,选择符两边的表达式的顺序对结果会有影响。假设你想用正则表达式搜索一个编程语言的函数列表:Get,GetValue,Set或SetValue。一个明显的解决方案是<<Get|GetValue|Set|SetValue>>。让我们看看当搜索SetValue时的结果。

因为<<Get>>和<<GetValue>>都失败了,而<<Set>>匹配成功。因为正则导向的引擎都是“急切”的,所以它会返回第一个成功的匹配,就是“Set”,而不去继续搜索是否有其他更好的匹配。

和我们期望的相反,正则表达式并没有匹配整个字符串。有几种可能的解决办法。一是考虑到正则引擎的“急切”性,改变选项的顺序,例如我们使用<<GetValue|Get|SetValue|Set>>,这样我们就可以优先搜索最长的匹配。我们也可以把四个选项结合起来成两个选项:<<Get(Value)?|Set(Value)?>>。因为问号重复符是贪婪的,所以SetValue总会在Set之前被匹配。

一个更好的方案是使用单词边界:<<\b(Get|GetValue|Set|SetValue)\b>>或<<\b(Get(Value)?|Set(Value)?\b>>。更进一步,既然所有的选择都有相同的结尾,我们可以把正则表达式优化为<<\b(Get|Set)(Value)?\b>>。

 

 

  1. 组与向后引用

把正则表达式的一部分放在圆括号内,你可以将它们形成组。然后你可以对整个组使用一些正则操作,例如重复操作符。

要注意的是,只有圆括号“()”才能用于形成组。“[]”用于定义字符集。“{}”用于定义重复操作。

当用“()”定义了一个正则表达式组后,正则引擎则会把被匹配的组按照顺序编号,存入缓存。当对被匹配的组进行向后引用的时候,可以用“\数字”的方式进行引用。<<\1>>引用第一个匹配的后向引用组,<<\2>>引用第二个组,以此类推,<<\n>>引用第n个组。而<<\0>>则引用整个被匹配的正则表达式本身。我们看一个例子。

假设你想匹配一个HTML标签的开始标签和结束标签,以及标签中间的文本。比如<B>This is a test</B>,我们要匹配<B>和</B>以及中间的文字。我们可以用如下正则表达式:“<([A-Z][A-Z0-9]*)[^>]*>.*?</\1>”

首先,“<”将会匹配“<B>”的第一个字符“<”。然后[A-Z]匹配B,[A-Z0-9]*将会匹配0到多次字母数字,后面紧接着0到多个非“>”的字符。最后正则表达式的“>”将会匹配“<B>”的“>”。接下来正则引擎将对结束标签之前的字符进行惰性匹配,直到遇到一个“</”符号。然后正则表达式中的“\1”表示对前面匹配的组“([A-Z][A-Z0-9]*)”进行引用,在本例中,被引用的是标签名“B”。所以需要被匹配的结尾标签为“</B>”

你可以对相同的后向引用组进行多次引用,<<([a-c])x\1x\1>>将匹配“axaxa”、“bxbxb”以及“cxcxc”。如果用数字形式引用的组没有有效的匹配,则引用到的内容简单的为空。

一个后向引用不能用于它自身。<<([abc]\1)>>是错误的。因此你不能将<<\0>>用于一个正则表达式匹配本身,它只能用于替换操作中。

后向引用不能用于字符集内部。<<(a)[\1b]>>中的<<\1>>并不表示后向引用。在字符集内部,<<\1>>可以被解释为八进制形式的转码。

向后引用会降低引擎的速度,因为它需要存储匹配的组。如果你不需要向后引用,你可以告诉引擎对某个组不存储。例如:<<Get(?:Value)>>。其中“(”后面紧跟的“?:”会告诉引擎对于组(Value),不存储匹配的值以供后向引用。

  • 重复操作与后向引用

当对组使用重复操作符时,缓存里后向引用内容会被不断刷新,只保留最后匹配的内容。例如:<<([abc]+)=\1>>将匹配“cab=cab”,但是<<([abc])+=\1>>却不会。因为([abc])第一次匹配“c”时,“\1”代表“c”;然后([abc])会继续匹配“a”和“b”。最后“\1”代表“b”,所以它会匹配“cab=b”。

应用:检查重复单词–当编辑文字时,很容易就会输入重复单词,例如“the the”。使用<<\b(\w+)\s+\1\b>>可以检测到这些重复单词。要删除第二个单词,只要简单的利用替换功能替换掉“\1”就可以了。

 

 

  • 组的命名和引用

在PHP,Python中,可以用<<(?P<name>group)>>来对组进行命名。在本例中,词法?P<name>就是对组(group)进行了命名。其中name是你对组的起的名字。你可以用(?P=name)进行引用。

.NET的命名组

.NET framework也支持命名组。不幸的是,微软的程序员们决定发明他们自己的语法,而不是沿用Perl、Python的规则。目前为止,还没有任何其他的正则表达式实现支持微软发明的语法。

下面是.NET中的例子:

(?<first>group)(?’second’group)

正如你所看到的,.NET提供两种词法来创建命名组:一是用尖括号“<>”,或者用单引号“’’”。尖括号在字符串中使用更方便,单引号在ASP代码中更有用,因为ASP代码中“<>”被用作HTML标签。

要引用一个命名组,使用\k<name>或\k’name’.

当进行搜索替换时,你可以用“${name}”来引用一个命名组。

 

  1. 正则表达式的匹配模式

本教程所讨论的正则表达式引擎都支持三种匹配模式:

<</i>>使正则表达式对大小写不敏感,

<</s>>开启“单行模式”,即点号“.”匹配新行符

<</m>>开启“多行模式”,即“^”和“$”匹配新行符的前面和后面的位置。

 

  • 在正则表达式内部打开或关闭模式

如果你在正则表达式内部插入修饰符(?ism),则该修饰符只对其右边的正则表达式起作用。(?-i)是关闭大小写不敏感。你可以很快的进行测试。<<(?i)te(?-i)st>>应该匹配TEst,但是不能匹配teST或TEST.

 

  1. 原子组与防止回溯

在一些特殊情况下,因为回溯会使得引擎的效率极其低下。

让我们看一个例子:要匹配这样的字串,字串中的每个字段间用逗号做分隔符,第12个字段由P开头。

我们容易想到这样的正则表达式<<^(.*?,){11}P>>。这个正则表达式在正常情况下工作的很好。但是在极端情况下,如果第12个字段不是由P开头,则会发生灾难性的回溯。如要搜索的字串为“1,2,3,4,5,6,7,8,9,10,11,12,13”。首先,正则表达式一直成功匹配直到第12个字符。这时,前面的正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11,”,到了下一个字符,<<P>>并不匹配“12”。所以引擎进行回溯,这时正则表达式消耗的字串为“1,2,3,4,5,6,7,8,9,10,11”。继续下一次匹配过程,下一个正则符号为点号<<.>>,可以匹配下一个逗号“,”。然而<<,>>并不匹配字符“12”中的“1”。匹配失败,继续回溯。大家可以想象,这样的回溯组合是个非常大的数量。因此可能会造成引擎崩溃。

用于阻止这样巨大的回溯有几种方案:

一种简单的方案是尽可能的使匹配精确。用取反字符集代替点号。例如我们用如下正则表达式<<^([^,\r\n]*,){11}P>>,这样可以使失败回溯的次数下降到11次。

另一种方案是使用原子组。

原子组的目的是使正则引擎失败的更快一点。因此可以有效的阻止海量回溯。原子组的语法是<<(?>正则表达式)>>。位于(?>)之间的所有正则表达式都会被认为是一个单一的正则符号。一旦匹配失败,引擎将会回溯到原子组前面的正则表达式部分。前面的例子用原子组可以表达成<<^(?>(.*?,){11})P>>。一旦第十二个字段匹配失败,引擎回溯到原子组前面的<<^>>。

 

  1. 向前查看与向后查看

Perl 5 引入了两个强大的正则语法:“向前查看”和“向后查看”。他们也被称作“零长度断言”。他们和锚定一样都是零长度的(所谓零长度即指该正则表达式不消耗被匹配的字符串)。不同之处在于“前后查看”会实际匹配字符,只是他们会抛弃匹配只返回匹配结果:匹配或不匹配。这就是为什么他们被称作“断言”。他们并不实际消耗字符串中的字符,而只是断言一个匹配是否可能。

几乎本文讨论的所有正则表达式的实现都支持“向前向后查看”。唯一的一个例外是Javascript只支持向前查看。

  • 肯定和否定式的向前查看

如我们前面提过的一个例子:要查找一个q,后面没有紧跟一个u。也就是说,要么q后面没有字符,要么后面的字符不是u。采用否定式向前查看后的一个解决方案为<<q(?!u)>>。否定式向前查看的语法是<<(?!查看的内容)>>。

肯定式向前查看和否定式向前查看很类似:<<(?=查看的内容)>>。

如果在“查看的内容”部分有组,也会产生一个向后引用。但是向前查看本身并不会产生向后引用,也不会被计入向后引用的编号中。这是因为向前查看本身是会被抛弃掉的,只保留匹配与否的判断结果。如果你想保留匹配的结果作为向后引用,你可以用<<(?=(regex))>>来产生一个向后引用。

  • 肯定和否定式的先后查看

向后查看和向前查看有相同的效果,只是方向相反

否定式向后查看的语法是:<<(?<!查看内容)>>

肯定式向后查看的语法是:<<(?<=查看内容)>>

我们可以看到,和向前查看相比,多了一个表示方向的左尖括号。

例:<<(?<!a)b>>将会匹配一个没有“a”作前导字符的“b”。

值得注意的是:向前查看从当前字符串位置开始对“查看”正则表达式进行匹配;向后查看则从当前字符串位置开始先后回溯一个字符,然后再开始对“查看”正则表达式进行匹配。

 

  • 深入正则表达式引擎内部

让我们看一个简单例子。

把正则表达式<<q(?!u)>>应用到字符串“Iraq”。正则表达式的第一个符号是<<q>>。正如我们知道的,引擎在匹配<<q>>以前会扫过整个字符串。当第四个字符“q”被匹配后,“q”后面是空字符(void)。而下一个正则符号是向前查看。引擎注意到已经进入了一个向前查看正则表达式部分。下一个正则符号是<<u>>,和空字符不匹配,从而导致向前查看里的正则表达式匹配失败。因为是一个否定式的向前查看,意味着整个向前查看结果是成功的。于是匹配结果“q”被返回了。

我们在把相同的正则表达式应用到“quit”。<<q>>匹配了“q”。下一个正则符号是向前查看部分的<<u>>,它匹配了字符串中的第二个字符“i”。引擎继续走到下个字符“i”。然而引擎这时注意到向前查看部分已经处理完了,并且向前查看已经成功。于是引擎抛弃被匹配的字符串部分,这将导致引擎回退到字符“u”。

因为向前查看是否定式的,意味着查看部分的成功匹配导致了整个向前查看的失败,因此引擎不得不进行回溯。最后因为再没有其他的“q”和<<q>>匹配,所以整个匹配失败了。

为了确保你能清楚地理解向前查看的实现,让我们把<<q(?=u)i>>应用到“quit”。<<q>>首先匹配“q”。然后向前查看成功匹配“u”,匹配的部分被抛弃,只返回可以匹配的判断结果。引擎从字符“i”回退到“u”。由于向前查看成功了,引擎继续处理下一个正则符号<<i>>。结果发现<<i>>和“u”不匹配。因此匹配失败了。由于后面没有其他的“q”,整个正则表达式的匹配失败了。

 

  • 更进一步理解正则表达式引擎内部机制

让我们把<<(?<=a)b>>应用到“thingamabob”。引擎开始处理向后查看部分的正则符号和字符串中的第一个字符。在这个例子中,向后查看告诉正则表达式引擎回退一个字符,然后查看是否有一个“a”被匹配。因为在“t”前面没有字符,所以引擎不能回退。因此向后查看失败了。引擎继续走到下一个字符“h”。再一次,引擎暂时回退一个字符并检查是否有个“a”被匹配。结果发现了一个“t”。向后查看又失败了。

向后查看继续失败,直到正则表达式到达了字符串中的“m”,于是肯定式的向后查看被匹配了。因为它是零长度的,字符串的当前位置仍然是“m”。下一个正则符号是<<b>>,和“m”匹配失败。下一个字符是字符串中的第二个“a”。引擎向后暂时回退一个字符,并且发现<<a>>不匹配“m”。

在下一个字符是字符串中的第一个“b”。引擎暂时性的向后退一个字符发现向后查看被满足了,同时<<b>>匹配了“b”。因此整个正则表达式被匹配了。作为结果,正则表达式返回字符串中的第一个“b”。

  • 向前向后查看的应用

我们来看这样一个例子:查找一个具有6位字符的,含有“cat”的单词。

首先,我们可以不用向前向后查看来解决问题,例如:

<< cat\w{3}|\wcat\w{2}|\w{2}cat\w|\w{3}cat>>

足够简单吧!但是当需求变成查找一个具有6-12位字符,含有“cat”,“dog”或“mouse”的单词时,这种方法就变得有些笨拙了。

我们来看看使用向前查看的方案。在这个例子中,我们有两个基本需求要满足:一是我们需要一个6位的字符,二是单词含有“cat”。

满足第一个需求的正则表达式为<<\b\w{6}\b>>。满足第二个需求的正则表达式为<<\b\w*cat\w*\b>>。

把两者结合起来,我们可以得到如下的正则表达式:

<<(?=\b\w{6}\b)\b\w*cat\w*\b>>

具体的匹配过程留给读者。但是要注意的一点是,向前查看是不消耗字符的,因此当判断单词满足具有6个字符的条件后,引擎会从开始判断前的位置继续对后面的正则表达式进行匹配。

最后作些优化,可以得到下面的正则表达式:

<<\b(?=\w{6}\b)\w{0,3}cat\w*>>

 

  1. 正则表达式中的条件测试

条件测试的语法为<<(?ifthen|else)>>。“if”部分可以是向前向后查看表达式。如果用向前查看,则语法变为:<<(?(?=regex)then|else)>>,其中else部分是可选的。

如果if部分为true,则正则引擎会试图匹配then部分,否则引擎会试图匹配else部分。

需要记住的是,向前先后查看并不实际消耗任何字符,因此后面的then与else部分的匹配时从if测试前的部分开始进行尝试。

 

  1. 为正则表达式添加注释

在正则表达式中添加注释的语法是:<<(?#comment)>>

例:为用于匹配有效日期的正则表达式添加注释:

(?#year)(19|20)\d\d[- /.](?#month)(0[1-9]|1[012])[- /.](?#day)(0[1-9]|[12][0-9]|3[01])

 

转自:http://dragon.cnblogs.com/archive/2006/05/09/394923.html