活到老学到老

现学现卖

博客园 首页 新随笔 联系 订阅 管理
我试了一下,貌似没有问题。当然也很可能有问题,因为正则表达式我也是刚入门。
这个表达式是这样的:
^
[^<>]*
((?'open'<[^<>]*)+
(?'close-open'[^<>]*>)+)+
(?(open)(?!))$
作用是判定一个字符串中的尖括号是否配对,如果都配对则返回整个串,否则不返回任何匹配。
首先写下这个东西:
^
Expr
$
表示进行整串匹配,也就是要判断整个字符串是否符合Expr表示的模式。
哦,使用这个正则表达式的时候记得开启忽略空白字符。
如果正则表达式支持宏多好,把<>修改为()时就不用费太多力气了。
Expr::=
    Expr1::=[^<>]*
    Expr2::=(
                      (?'open'<[^<>]*)+
                      (?'close-open'[^<>]*>)+
                 )+
   Expr3::=(?(open)(?!))

[^<>]*不用多说,匹配'<'和'>'之外的任意字符任意多次,这并不是关键。
关键是Expr2。
Expr2中有两个关键构造,(?'Name'Expr)和(?'Name2-Name1'Expr)
第一个我称之为显式命名组,第二个人们称为平衡组。
这是.net framework特有的构造。
显式命名组将捕获到的文本存入名称为Name的堆栈中。所谓捕获到的文本,就是Expr所匹配的文本,(?'Name'Expr)和Expr的区别在于Expr捕获的文本没有存到一个堆栈中,或者说没有存到一个组中。
(?'Name2-Name1'Expr)除了将文本捕获到Name2组中,还pop名为Name的堆栈。
现在我们可以看看Expr2,其意义是“<[^<>]*”至少重复一次,后跟至少一个“[^<>]*>”。具几个匹配这个模式的例子:
<fsd<rew<bvc rewrew>ewr>
然后这整个东西---------->>   (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+  <<----------可以重复多次。
可能说的不是太清楚,我觉得这一步很关键:
<[^<>]* 的实例可以是:<fsdfds、<、<rewrewrew、<fdsfsd dfsfds。
[^<>]*>的实例可以是:fdsfsd>、>、w-ww>。
现在你可以想象出来(<[^<>]*)+ ([^<>]*>)+是什么了。
而 (?'open'<[^<>]*)+(?'close-open'[^<>]*>)+  和它的唯一区别是,(?'open'...每匹配一次,就push该匹配结果到名为open的堆栈,(?'close-open'...每匹配一次,就从open堆栈pop一个元素。open堆栈是<与>是否配对的指示器。
最后Expr3这一部分判断open堆栈是否为空,为空则匹配成功,否则前向断言(?!),这总是导致匹配失败。





posted on 2008-03-04 18:41  John Rambo  阅读(922)  评论(1编辑  收藏  举报