ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 3763|回复: 7

[原创] VBScript.RegExp正则对象突破后发零宽断言的限制

[复制链接]

TA的精华主题

TA的得分主题

发表于 2019-1-1 23:17 | 显示全部楼层 |阅读模式
每个学习正则表达式的人,在刚开始入门的时候,就会被告知:VBScript.RegExp正则对象不支持“后发零宽断言”(也有的称之为“逆序环视”)的表达式。

虽然VBScript.RegExp正则对象不包含这样一个重要的特性,但是,它仍然在Jscript等编程语言中长期使用。由此,我们可以想象到,使用VBScript.RegExp正则对象,应当也是有办法可以解决“后发零宽断言”的问题。

因此,我经过大量实验,总结出了一种让VBScript.RegExp正则对象突破“后发零宽断言”的方法
这种方法,我称为“优先匹配排除法”,主要实现方式又分有两种:第1种、用"|"运算符来界定优先匹配的表达式子项;第2种、用懒惰匹配和贪婪匹配两者结合来界定优先匹配的表达式子项。

当然,具体使用哪一种,需要视具体的问题来分析而定。只要方法得当,可以应对几乎所有通常需要用“后发零宽断言”的表达式才能完成的匹配。
之所以只是说“几乎”,是因为我虽然成功地用这种方法做到了很多通常需要以“后发零宽断言”表达式来完成的匹配,但我不能完全排除有无法用它解决的“后发零宽断言”匹配要求的问题存在。

下面,就以一个具体的例子,由简入繁地逐步展示这种方法。


批注 2019-01-01.png

附件:

正则后发零宽断言.rar (23.88 KB, 下载次数: 201)

评分

8

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-3 14:37 | 显示全部楼层
1楼的附件所举的例子,是提取字符串中符合条件的“连续字符串”,而且都是在默认这些“连续字符串”都是自成一体、不可拆分的前提条件下进行匹配。

如果没有上述默认限制的条件,则有可能匹配到更多的连续数字。

为了演示这两种情况下对应的正则表达式的写法,重新制作一个附件,如下所示。
此外,在重新制作此附件的过程中,我发现我原来总结的第一版正则表达式万能公式:

  1. [\s\S]*?(eXp)|[s\S]+
复制代码

还可以更进一步简化、优化,从而得到升级版的正则表达式万能公式:
  1. (eXp)|[\s\S]+?
复制代码


因此,我把升级版的正则表达式万能公式的用法也添加到本附件中。
又根据此发现,发表了新的相关主题帖子,具体请见:正则表达式万能公式进化版之——“唯我独尊”(出处: ExcelHome技术论坛)
在这个帖子中,我简明扼要地介绍了升级版的正则表达式万能公式的特点、以及它与第一版万能公式的关联与区别。

正则后发零宽断言(添加万能公式升级版解法).rar (31.63 KB, 下载次数: 159)


TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-3 18:30 | 显示全部楼层
本帖最后由 ggmmlol 于 2019-1-3 18:44 编辑

“零宽断言”最经典应用实例——为字符串中的浮点数添加千位分隔符“,”

为什么说“为字符串中的浮点数添加千位分隔符”的问题是最经典应用实例呢?
我们先来分析一下这个问题:
1) 添加千位分隔符,要求明确是“添加”,因此,它要求保留原有全部的字符,这就要求表达式通常只能匹配特定的位置而不能任何消耗字符,而这正是“零宽断言”的本义;
2)添加千位分隔符的位置必须符合以下两项特定条件:
a、它的后面必须“恰好是3n个数字字符(这里要求n必须是正整数)”
这一条就包含了“正向”和“负向”两种形式的“先行零宽断言”,而且是嵌套式的,具体如下:
  1. (?=(\d{3})+(?!\d))
复制代码
b、它的前面必须是1个或以上的连续数字,而且因为千位分隔符只能添加在浮点数的整数部分之中,而不能添加在小数部分之中,因此,在它前方的连续数字之前又必须限定为不能紧挨着小数点。这样一来,就又要用到通常所称的“后发零宽断言”,而且也包含“正向”和“负向”两种,具体是:
  1. (?<!\.\d+)(?<=\d+)
复制代码
综合起来,就是:
  1. (?<!\.\d+)(?<=\d+)(?=(\d{3})+(?!\d))
复制代码
从上面这个表达式可以看出,它用到了“零宽断言”的所有4种形式:先行正向零宽断言、先行负向零宽断言、后发正向零宽断言、后发负向零宽断言。
这个表达式的正确性,可以用RegExBuddy这款软件使用支持所有零宽断言形式的.Net正则表达式引擎来测试确定,如下图所示(其中,还额外添加条件排除了以年结尾的整数):

零宽断言.png

可见,把用正则表达式解决“浮点数添加千位分隔符”的问题称为零宽断言表达式应用的“最经典实例”是绝对名副其实的。


TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-3 18:40 | 显示全部楼层
本帖最后由 ggmmlol 于 2019-1-3 18:45 编辑

但是,VBScript.RegExp正则对象不支持“后发零宽断言”的,那要用它来解决上述经典问题,又该如何实现呢?

话不多说,直接上代码,欢迎大家测试、品评!

  1. Sub Test()
  2.     Dim s$
  3.     s = "公元480年左右,南北朝时期的数学家祖冲之进一步得出精确到小数点后7位的结果," _
  4.         & Chr(10) & "给出不足近似值3.1415926和过剩近似值3.1415927,还得到两个近似分数值,密率355/113和约率22/7。" _
  5.         & Chr(10) & "密率是个很好的分数近似值,要取到52163/16604才能得出比355/113略准确的近似。" _
  6.         & Chr(10) & "到1948年英国的弗格森(D. F. Ferguson)和美国的伦奇共同发表了π的808位小数值,成为人工计算圆周率值的最高纪录。" _
  7.         & Chr(10) & "下面给出圆周率的前100位小数:π=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
  8.     Debug.Print s
  9.     s = 千分位(s)
  10.     Debug.Print
  11.     Debug.Print s
  12.     MsgBox s
  13. End Sub

  14. Function 千分位(ByVal s$)
  15.     With CreateObject("VBScript.RegExp")
  16.        .Global = True
  17.         .Pattern = "((?:\.\d+[\s\S]*?)*\d)(?=(?:\d{3})+(?!\d|年))"
  18. '        .Pattern = "((?:\.\d+[\s\S]*?)*\d)(?=(?:\d{3})+(?!\d))"
  19.         s = s & "A9999A" '构造结尾字符
  20.         s = .Replace(s, "$1,")
  21.         s = Left(s, Len(s) - 7) '消除构造添加的结尾字符
  22.         千分位 = s
  23.     End With
  24. End Function
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-1-3 19:36 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
4楼所示的添加千位分隔符的自定义函数中用到的正则表达式,是根据我自己总结的正则表达式万能公式第一版进行推理、验证而得到的。
它的第一次发表, 是对一位本论坛会员的求助贴子的回复中,见以下主题帖子的11楼和17楼:
http://club.excelhome.net/forum. ... 320&pid=9696335
可惜的是,这位求助者因为看不懂这条正则表达式,于是就认为它别扭、不合理,反而来了一通冷嘲热讽,让我颇为无奈。

后来,又有一位会员求助千分位的问题,我在他的帖子的7楼做了最接近于以上代码的回复:
[求助]千分位-正则表达式
http://club.excelhome.net/thread-1451761-1-1.html
而这位坛友也表示没有看懂其中的正则表达式。

如此说来,用VBS的正则对象解决“后发零宽断言”的问题,还是颇有难度的。
但是,我相信,只要仔细体会了我所总结的正则表达式万能公式的原理、思想,就一定能够通过这个公式,以“套路”化的招数,轻松解决实际问题了。这也正是正则表达式万能公式的意义所在。


TA的精华主题

TA的得分主题

发表于 2020-2-4 14:32 | 显示全部楼层
这个确实需要好好琢磨,感谢楼主讲解

TA的精华主题

TA的得分主题

发表于 2020-9-4 09:05 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2020-9-9 19:58 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-27 02:38 , Processed in 0.039654 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表