总结
本期竞赛题,主要考察对VBS正则表达式知识的综合运用。
第一节、审题分析。
1、本题目的目标,概括起来,就是要求把多个特定位置字母'e'替换为数字字符'2'。 对于这种问题,常规的解决办法是:使用循环语句,把源字符串中符合条件要求的'e'逐一找出来,并改写为'2'。但是答题要求中,禁止在新添加的代码中使用循环语句或有循环执行代码功能的语句,所以此路不通。 2、如果不使用循环而对一个字符串的多处字符进行替换,还有以下3种工具可用:a)工作表的替换函数SUBSTITUTE;b)单元格区域的替换方法Replace;c)VBA的替换函数Replace,但这3种方法对于目标字符的匹配能力有限,它们都可以把字符串的每个字母'e'都替换成一个数字字符'2',但做不到选择性地排除那些不符合题目要求的字母'e'。所以,这种方法仍然行不通。 3、在VBA代码中,能够不用循环语句、而对字符串中符合特定规则的多处字符一次性进行精确匹配和替换的工具,只有“正则表达式”对象。 4、现有的高级编程语言几乎都有各自可以使用的正则表达式引擎,这些引擎的功能强弱不一。一些功能较全面的高级正则表达式引擎,可以同时支持“顺序”和“逆序”两种零宽断言的分组,如果使用这种高级正则表达式引擎来解答本问题,就会非常简单。比如,用.Net平台的公用的正则表达式引擎,可以把本题目源字符串中的目标字符(即:紧接在任意两个数字字符之间的连续的一个或多个字母'e'中的每一个e”)以正则表达式精准地描述为:(?<=\de*)e(?=e*\d)使用它的Replace方法,就可以实现准确替换。如下图中用RegexBuddy测试软件所示: 5、但是,本题目的答题要求中,又规定只可以使用VBA语言,禁止直接或间接引用其它编程语言。这样一来,想要引用其它编程语言中的高级正则表达式引擎的路子也是行不通了。分析至此,有一个初步结论:唯有使用VBA语言中可以直接引用的正则表达式引擎的解法才能完全实现本题要求。
6、按第5步分析的结论,需要寻找在VBA语言中可以直接引用的正则表达式引擎,及其相应的具体解决方案。其一,是VBA语言可以直接引用的高级正则表达式引擎,比如本论坛中有过介绍的“增强的正则表达式引擎”NewXing.RegExp;其二,是VBA语言可以直接引用的“VBScript.RegExp”正则表达式引擎。 7、如果引用NewXing.RegExp正则表达式引擎,由于它同时支持“顺序”、“逆序”两种形式的零宽断言分组,按第4步分析的结果,可以确定此方式是能够解决本问题,而且代码也很简单,即便是从没有使用过它的VBAer,在查看过它的帮助文档后也可以正确完成解答,具体代码就不在此列出了。但是,此方式有2点局限:NewXing.RegExp是由第三方应用软件提供的,所以需要安装相应的软件才能使用;而且该软件目前只有32位版本,因此在64位的Office环境中就无法使用了。因为它的此项局限性,如果使用它来解答本问题,将不能获评满分。
8、所以,需要寻找VBA中可以直接引用、且同时兼容于32位和64位的Office环境的正则表达式引擎,目前实际上也仅有“VBScript.RegExp”正则引擎符合这两个要求。但是,在它的帮助文档中,说明它只是“提供简单的正则表达式支持功能”,而不是“全面”的功能。与本题目相关的,就是它不支持“逆序零宽断言”的分组,也就是说,表达式'(?<=\de*)'对于它是无效的,必须把这个表达式转换成VBScript.RegExp支持的且等效的表达式,才能完整地解决本问题。(见下图所示,VBScript.RegExp正则表达式语法所支持的4种分组模式)。 9、经过以上8个步骤的分析,可以看出:本竞赛题根本目标,就是要为“VBScript.RegExp”正则表达式引擎,找出一个突破其“逆序”零宽断言限制的通用方法。现在已知“VBScript.RegExp”正则表达式引擎支持“捕获”分组,以及“顺序零宽断言”的分组,它们都可以用来确定特定的位置,如果可以把“逆序零宽断言”的分组转换成等效的“捕获”分组或“顺序零宽断言”的分组,问题就可以得到解决。这也是解决本题的基本思路。
|