VBA正则表达式入门与提高 下载本文

正则表达式入门与提高

它总是匹配一行中换行符前所有的文本. 实例:提取科室名 目标文本:

姓名:张三 科室:人事科(科长) 姓名:李四 科室:保卫科(干事) 正则表达式: 科室:(.*) 代码: Sub testname() Dim reg, mh, s$

s = \姓名:张三 科室:人事科(科长)\姓名:李四 科室:保卫科(干事)\ Set reg =CreateObject(\ reg.Pattern = \科室:(.*)\ reg.Global = True Set mh = reg.Execute(s) MsgBox mh(0).SubMatches(0) MsgBox mh(1).SubMatches(0) End Sub 讨论:

当用\科室:(.*)\去匹配文本时,在第一行成功匹配到:\科室:\后,正则的(.*)部分将依次匹配到后面跟着的所有字符,直到英文句点不能匹配的换行符.所以括号捕获到的内容是:人事科(科长).

而Global属性设置为true,表示找到第一个匹配后,只要还有文本没有尝试,那么,它将继续找出其它所有匹配结果. 在这个例子,找到两个匹配分别为mh(0)和mh(1). 其科室名即括号捕获的内容分别保存在这两个匹配的特殊变量$1中,VBA可以利用Match对象的submatches属性提取它们.(提示:如果不明白代码意思,请回到第一篇第二章查阅)

五.正则元字符—-字符(串)位置表示法

正则提供了一些表示位置元字符(序列),它可以锚定特定字符(串),有时使用它们可以提高匹配效率.除了前面介绍的^和$外,还有:

27

VBA平台的正则学习参考资料

(一)单词分界符\\b

在英文环境中,匹配一个字边界,即字与空格间的位置。例如,“er\\b”匹配“never”中的“er”,但不匹配“verb”中的“er”。

它匹配这样一个位置:该位置一边是英文单词字符,另一边不是.也可以理解为该位置两边的字符,其中一个可以被\\w匹配,另一个字符则可被\\W匹配.所以在英文环境中,可匹配四种位置 (本文中英文单词字符指[a-zA-Z0-9_]):

1) 在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”) 2) 在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”) 3) 在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后 4) 在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面 下面这个例子可让你明白单词分界符的用途: 目标文本:He captured a catfish for his cat 正则表达式1: cat

正则表达式2: \\bcat\\b

任务要求:用字符串fat,替换文本中的cat. 代码: sub test() dim s$

with createobject(\ .pattern=\分别用上面两个表达式测试 .global=true

s=.replace(\

28

正则表达式入门与提高

end with msgbox s end sub

你能分析结果差异的原因吗?

(二)非单词边界\\B

非字边界匹配。“er\\B”匹配“verb”中的“er”,但不匹配“never”中的“er”。 它是\\b取反.\\B总是匹配两个同时被\\w或\\W匹配的字符之间的位置.它匹配下列位置: 1)在目标文本的第一个字符之前如果第一个字符不是单词字符; 2)在目标文本的最后一个字符之后,如果最后一个字符不单词字符; 3)在两个单词字符之间; 4)在两个非单词符之间; 5)空串

在非英文环境中,没有单词边界;全部是非单词边界.所以应用范围很窄.

(三)肯定顺序环视与否定顺序环视

以一个实例来讨论: 1) (?=98) 2) (?!98)

第一个是肯定环视,表示子字符串”98”前面的位置;第二个是否定环视,表示不是子字符串”98”的位置.

例:

目标文本:”window97升级为window98”

如果把它们作为正则表达式作用于该文本,则该文本中只有”98”前一个位置上才能被(?=98)匹配;除这个位置外,其它所有位置都可以被(?!98)匹配.它的工作原理是:

在每个位置上查找该位置后是否跟着一个字符9,再然后再跟着一个字符8.如果是,则(?=98)报告匹配成功,(?!98)报告匹配失败;反之,(?=98)报告失败,(?!98)报告成功.

利用它们可以锚定特定字符串,如:正则表达式 Window(?=98)

29

VBA平台的正则学习参考资料

表示匹配后面跟着字符串”98”的字符串”window”.如果用它作用于上面目标文本,那么它只能匹配window98前面的”window”.

而正则表达式: Window(?!=98)

表示匹配后面没有跟着字符串”98”的字符串”window”.如果用它作用上面目标文本,那么它它只能匹配widow97前面的”window”

环视只是简单地测试其中子表达式能否在当前位置匹配后面的文本.无论是什么样的结果,它都不会”占有”被测试的文本.例:

目标文本:”正则ABC” 正则:(?!=\\W+).{2} 代码: Sub test() Dim re,mh,s$ S=”正则ABC”

With createobject(“vbscript.regexp”) .pattern=”(?=\\W+).{2}” Set mh=.Execute(s) End with For each k in mh Debug.print k ' “正则” next End sub 讨论:

匹配结果是:”正则”.我们来分析一下匹配过程:

在文本的开始位置,正则引擎首先尝试(?!=\\W+),即检查该位置后面有无一个或一个以上的非英文单词字符.结果它找到\正则\二个字符是非英文字符,引擎报告第一个子表达式匹配成功;接着尝试第二个子表达式:”.{2}”,即匹配两个任意字符,这两个字符就是”正则”.正则表达式中子表达式尝试完毕,最后报告成功而结束.

我们看到(?!=\\W+),并没有”消耗”掉”正则”字符串,如果消耗了,那么结果应该是”AB”.

最后要指出一点的是:虽然环视表达式中有圆括号,但它是非捕获性的.并且圆括号与?、!或=是一个不可分割的整体.

30