ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

用正则表达式去重

[复制链接]

TA的精华主题

TA的得分主题

发表于 2020-2-28 19:00 | 显示全部楼层 |阅读模式
代码测试英文的结果没有问题,但是换成中文的就不行。。对正则不熟,请大神指教

正则去重.rar

13.37 KB, 下载次数: 145

TA的精华主题

TA的得分主题

发表于 2020-2-28 19:13 | 显示全部楼层
本帖最后由 duquancai 于 2020-2-28 19:37 编辑

为啥要用正则表达式去重???
  1. Sub Demo()
  2.     Dim d As Object, k
  3.     Set d = CreateObject("Scripting.Dictionary")
  4.     For Each k In Split([a2].Value, "、"): d(k) = Empty: Next
  5.     MsgBox Join(d.Keys(), ",")
  6. End Sub
复制代码
QQ截图20200228192144.png

TA的精华主题

TA的得分主题

 楼主| 发表于 2020-2-28 20:07 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
学习呗,能用字典 我还纠结这个干嘛。。。

TA的精华主题

TA的得分主题

发表于 2020-2-28 21:12 | 显示全部楼层
[技巧]正则表达式万能公式应用实例:在一个字符串内按分隔符提取不重复项
http://club.excelhome.net/thread-1486825-1-1.html
(出处: ExcelHome技术论坛)

TA的精华主题

TA的得分主题

发表于 2020-2-28 22:36 来自手机 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 adasa 于 2020-3-1 18:36 编辑
duquancai 发表于 2020-2-28 19:13
为啥要用正则表达式去重???

这个代码是用什么写的?

TA的精华主题

TA的得分主题

发表于 2020-2-28 22:51 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
  1. Sub RegExpDemo()
  2.     Dim strTxt As String
  3.     Dim objRegEx As Object
  4.     Set objRegEx = CreateObject("vbscript.regexp")
  5.     objRegEx.Pattern = ".*?(?:^|、)([^、]+)(?=、*$|(、))(?!.*、\1(、|$))|.+"
  6.     objRegEx.Global = True
  7.     strTxt = [a2].Value
  8.     MsgBox objRegEx.Replace(strTxt, "$1$2")
  9.     Set objRegEx = Nothing
  10. End Sub
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-2-29 09:07 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
可以請6樓說明一下Pattern各個括號內或之外的意義嗎?
已了解意義大概如下
.* 是任何字群 但不了解.*? 作用  為何多了?
$1 是Pattern 第1個括號(   ) 內容  但不了解單個 $ 作用 是不是^開頭的相反結尾
?= 是lookaheand
?! 是negative lookaheand  但不了解?: 是什麼
| 是 or 或是   
[   ] 是方括號內任1字均可
.+ 是任何字群 但不了解與.*差別  Pattern的最尾處
^ 不從開頭

TA的精华主题

TA的得分主题

发表于 2020-2-29 09:34 | 显示全部楼层
'数据量很小直接循环效率也不差,,,

Option Explicit

Sub test()
  Dim arr, t, i, j, k, m
  arr = [a1].CurrentRegion.Resize(, 1).Value
  For i = 1 To UBound(arr, 1)
    t = Split(arr(i, 1), "、"): m = 0
    For j = 1 To UBound(t)
      For k = 0 To m
        If t(k) = t(j) Then Exit For
      Next
      If k = m + 1 Then m = m + 1: t(m) = t(j)
    Next
    ReDim Preserve t(m)
    arr(i, 1) = Join(t, "、")
  Next
  [c1].Resize(UBound(arr, 1)) = arr
End Sub

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2020-2-29 13:42 | 显示全部楼层
本帖最后由 ggmmlol 于 2020-2-29 14:02 编辑


image.png

正则表达式中的成对括号所包含的表达式,称为“分组”。
如图所示,“分组”可划分“捕获”与“非捕获”两大类;
而后者“非捕获”分组又可按是否消耗字符这一特征进一步划分为“非零宽断言”和“零宽断言”两类,
其中的“零宽断言”,又可以进一步划分为“先行”和“后发”两类,这两者又可以分别划分为肯定式和否定式两类。
因此,对于功能最完善的正则表达式引擎来说,“分组”的具体表现形式共有6种。
而VBScript.RegExp,只是一种较基础的正则表达式引擎,它不支持后发零宽断言的分组,所以,它只可以用到上图中的前4种分组。


为什么要把分组搞得这么复杂呢?这是为了分析字符串中的目标字符的特征而设计的。


对于任意字符串中的目标字符,都可以从它的“自身”、“前缀”和“后缀”3个方面来概括它的特征。
对于一些规则简单的“目标字符”,往往只需要从它“自身”的这一项特征就能表示出来,比如提取字符串中的数字,它自身的特征就是字符“0-9”;
而一些复杂的“目标字符”,比如本题目中,要提取的目标字符是:以顿号分隔的字符的不重复项,这是一个复杂的规则,需要综合使用它的“自身”、“前缀”、“后缀”用到全部3个方面的特征才能准确地表示出来。

目标字符的“自身”,是我们需要获取的,因此要使用“捕获分组”来获取;而它的“前缀”、“后缀”,通常都不是需要获取的,所以要以“非捕获分组”来表示。
一个目标字符的“后缀”字符,有可能还同时是下一个目标字符的“前缀”字符,而字符串中的任意一个字符,在正则表达式中被匹配时,都只能被消耗一次,又因为VBScript.RegExp引擎是从左向右匹配的,而且它不支持“后发零宽断言”,因此,在“前缀”的表达式中,只能使用“非零宽断言”的表达式,这就必然消耗字符,因此,在“后缀”的表达式部分,就不允许再次消耗字符,也就必须用“零宽断言”的分组来匹配,以留做下一目标字符的“前缀”的“非零宽断言”的表达式来消耗。


具体到本题,目标字符的“自身”是多个连续的非顿号字符,即[^、]+
目标字符的自身是我们需要获取的,因此要用捕获分组表示:([^、]+)
目标字符是以顿号分隔的,因此,它的“后缀”是顿号或字符串结尾位置,按前面的分析,它需要以“零宽断言”的分组来表示,即(?=、*$|(、))
其中,非字符串结尾处的目标字符的“后缀”顿号需要捕获以做为目标项之间的分隔符。
同理,它的“前缀”是顿号或字符串的开始位置,即、|^
“前缀”不是必须获取的,所以,通常使用非捕获的分组,而为了加快匹配效率,要尽可能地消耗字符,综合起来,所以就使用可消耗字符的“非零宽断言”的“非捕获分组”(?:、|^)
此外,本题目的目标字符是“去重复”的项,也就是说,目标字符的后面不再出现与这个目标字符即第1个捕获分组相同的项,因此,“后缀”还需要增加一个后向引用的表达式来表示,即(?!.*、\1(、|$))


把目标字符的特征按“前缀”、“自身”、“后缀”的顺序连接起来,再考虑到它们的每一个的前面可能存在不确定长度的其它任意字符.*,为了确保目标字符被优先匹配,这些出现在前面的不确定的任意字符必须加以“懒惰”限定符,即.*?
最后,在最末一个目标字符之后,还可能剩余多个其它任意非目标字符,由于这一项是最后出现的,优先级已经最低了,不用担心挤占目标字符,因此,可以使用贪婪限定符来表示并以“或”运算符(含义应理解为else,即“否则”)与前面的表达式相连,即|.+
把所有的各部分表达式按先后顺序连接起来,得到最终的完整的正则表达式.*?(?:、|^)([^、]+)(?=、*$|(、))(?!.*、\1(、|$))|.+
执行正则替换时,替换为“$1$2”,即保留第1个和第2个捕获分组。其中,第2个捕获分组是嵌套在第1个零宽断言的分组之内。

总结:本题目用正则表达式来解决,需要综合运用VBScript.RegExp所支持的全部4种分组形式,并且还要运用分组的“后向引用”,以及分组的嵌套,此外,还要运用“懒惰”与“贪婪”两种限定符以及“或”运算符来界定匹配的优先级。因此,它是正则表达式的集大成之作。吃透本题对于目标字符的“自身”、“前缀”、“后缀”特征的逐项分析方法,以及优先级的限定匹配方法,可以提升对于正则表达式的理解。


评分

3

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

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

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

GMT+8, 2024-4-25 19:54 , Processed in 0.035482 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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