ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[原创] [技巧]正则表达式万能公式应用实例:在一个字符串内按分隔符提取不重复项

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2019-7-4 22:13 | 显示全部楼层 |阅读模式
实际工作中,经常遇到:在同一个字符串中以某种字符分隔出来的若干项,需要提取其中的不重复项。
这种问题的常规解决方法是:以Split函数拆分成数组,然后以字典对象获取不重复项,再以Join函数连接完成。

而另一种思路,则是利用正则表达式对象对于字符串的强大分析能力来完成提取,这需要熟练掌握正则表达式的“后向引用”和“先行零宽断言”等高级技巧,才能够正确实现。

话不多说,直接上图和附件:
提取不重复项.rar (13.65 KB, 下载次数: 652)

同一字符串内不重复项的提取.png



评分

12

查看全部评分

TA的精华主题

TA的得分主题

发表于 2019-7-4 23:17 | 显示全部楼层
牛皮!!!!!
一直以为自己掌握了正则基本用法,但看了楼主的例子,感觉读起来好吃力。。。。。理解力-max了

TA的精华主题

TA的得分主题

发表于 2019-7-5 00:13 | 显示全部楼层
.*?(^|;) 有点不理解,这个 ^ 在不转义情况下一般表示目标文本开始位置 或 放在中括号里做否定字符组元素,放在这里起到什么作用?

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-7-5 21:41 | 显示全部楼层
DevilW 发表于 2019-7-5 00:13
.*?(^|;) 有点不理解,这个 ^ 在不转义情况下一般表示目标文本开始位置 或 放在中括号里做否定字符组元素 ...

按我提出的正则表达式万能公式:.*?(eXp)|.+
这里的eXp是一个正则表达式变量,在本例中,它需要直接匹配“以分号间隔的非空不重复字符项”
所以eXp的基本特征是:
1、它自身是由至少一个以上的非分号的字符组成,即:([^;]+)
2、它的前面必须是分号或源字符串的开始位置,即:(^|;)
3、它的后面必须是分号或源字符串的结束位置,即表达式3:(?=;|$)
以上按前后顺序连接起来,即(^|;)([^;]+)(?=;|$)

这样的字符项有可能是重复的,而目标要求只取其中的不重复项(相同者只取最后一个)
因此,还需要给它加上一个限制条件:
(?!.*;\2(;|$))

因此:(eXp) = "(^|;)([^;]+)(?=;|$)(?!.*;\2(;|$))"
如果使用正则表达式的Execute方法,则.Pattern = eXp即可;
而使用正则表达式的Replace方法,就把(eXp)代入本回复开头所给出的万能公式,即:
.*?(^|;)([^;]+)(?=;|$)(?!.*;\2(;|$))|.+

这时,正则表达式Replace方法的第二参数可以是 "$2;",所得到的结果基本与期望结果相符,但是,当源字符串是以分号";"结束时,所得结果的后面出现两个多余的分号";;",
如果想只用一次正则替换就完美解决(即不产生多余的分号),本例中可以使用一个特殊的技巧,即正则表达式Replace方法的第二参数中的分隔符不使用常量";",而是用变量$3来从源字符串中捕获得到。
因为,对于所有的不重复项,根据其后面所接字符的情况,可以分作两类:一是除了最后一项之外的项,它们都必然各自后接一个以上的分号";"作为分隔符;第二类就只有最后那个,它必然后接任意多个分号";"之后达到结束位置。

为此,我们在表达式3添加一个捕获分组,把分号";"捕获起来,成为"(;)",并根据匹配优先级的需要,调整分支选择运算符的顺序,改成:(?=;*$|(;))

这样,当$3捕获时,对于上面所说的第一类,会捕获到一个分号";",对于第二类即最后一项,则会在前一个分支选择时就完成匹配,使得$3捕获的是空字符串。此外,当源字符串以一个以上的分号";"结束时,这些分号会被表达式最后的分支部分".+"所匹配,而这次匹配时,$2和$3两个子表达式所捕获的都是空字符串。因此,最终,不会在末尾部分产生多余的分号。

最终的表达式是:
.*?(^|;)([^;]+)(?=;*$|(;))(?!.*;\2(;|$))|.+

如果有细心的坛友,可能发现这个最终表达式与我在1楼给出的附件中公式一所使用的表达式并不完全一致,后者还在表达式开始位置添加了一个分支表达式";+$|",但是,你用最终表达式代入工作表的公式中,会发现这个最终表达式也是正确的。这也证明了万能公式的正确性。实际上,表达式";+$|"匹配的是源字符串最后可能出现的多个分号,它在本例中,是优先级最低的"|.+"的特例形式,而且因为它与另外的分支匹配项都是互斥的,因此可以写在任何分支位置。反过来,通用形式"|.+"则只能放在最后,否则它一旦开始匹配,将匹配消耗掉所有字符,导致它后面的分支匹配完全无效。

最后,在1楼附件的公式二里面,也有一个完全多余的分支匹配,感兴趣的坛友可以试着找出来。最先回复正确答案的坛友,将会获得我献上的3朵玫瑰花哦!

评分

3

查看全部评分

TA的精华主题

TA的得分主题

发表于 2019-7-6 03:29 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-7-6 13:33 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 ggmmlol 于 2019-7-6 13:56 编辑
dgenson 发表于 2019-7-6 03:29
大师是这个吗^;+

你回答正确:附件表格公式二里面的分支匹配的表达式字符^;+|是冗余的,可以去除。
3朵玫瑰送上了!



另外,对于前面坛友对表达式里面.*?(^|;)的疑问,特地说明如下:
看我4楼的解释中的这一句:
2、它的前面必须是分号或源字符串的开始位置,即:(^|;)
因此,当“^”前面没有转义符“\”,且不是在字符集运算符中以[^c]形式出现的话,那它就是匹配源字符串的开始位置


至于前面的.*?,那只是套用万能公式时添加的,用来匹配那些目标字符之前可能出现的既不确定内容也不确定长度的 非目标字符;
.*?(^|;)这个表达式的结果,按VBS正则表达式的运算法则,它等效于(^|.*?;),只是后面这种形式与万能公式相比略有形态的改变,不便于按万能公式的套路来理解。

TA的精华主题

TA的得分主题

发表于 2019-7-6 14:24 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
ggmmlol 发表于 2019-7-5 21:41
按我提出的正则表达式万能公式:.*?(eXp)|.+
这里的eXp是一个正则表达式变量,在本例中,它需要直接匹配 ...

果然,对于一个复杂的正则,还是由原作者进行分拆解说更容易理解一些。自己一点一点读的话真的是太难受了

TA的精华主题

TA的得分主题

发表于 2019-7-12 13:10 | 显示全部楼层
ggmmlol 发表于 2019-7-6 13:33
你回答正确:附件表格公式二里面的分支匹配的表达式字符^;+|是冗余的,可以去除。
3朵玫瑰送上了!

大师太牛了,你这短短10几个字符我研究了几天还没弄懂,现向您请教几个问题,见下图,
1.在替换时用$2$3是引用的捕获的第二三个括号的数据这个我应该没理解错,但在测试中第三个捕获的数据却显示空值这是为什么不应该是(;)号吗?第4个也是空值我试着用$2$4来替换却真的是替换成了空?
2.*?(^|;)([^;]+)(?=;*$|(;))(?!.*;\2(;|$))这个代码匹配原则我是这样理解的,查找一个在开始位置或分号开头后面1到多个不是分号的字符直到后面出现分号或结束的位置并且后面不是一组跟前面括号重复的值。分组后面没有跟重复量词那不应该每两个分号之间捕获一个值(如此例就是每个银行名字为一个item)吗,为什么第一个item里面有4个银行的值。愿在师能解惑送上鲜花聊表敬意

救解例图

救解例图
无标题.png

TA的精华主题

TA的得分主题

发表于 2019-7-13 11:14 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-7-13 11:51 | 显示全部楼层
举例说字符串都有分隔符的,split 后用字典 去重,更简单易行。
如果常规操作 很难实现目的,再考虑 正则吧。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

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

GMT+8, 2024-12-24 00:01 , Processed in 0.043836 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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