(1条消息) VBA正则表达式深度解析
目录
本文章可以学到:
先上代码:
分析:
调式:
细心一点会发现两个问题:
一个一个的来解答
本文章可以学到:
VBA正则表达式匹配第N个结果
VBA正则表达式剔除匹配包含字符的数字中剔除字符,只保留数字
先上代码:
Function GetStr(ByVal rng As String, str As String, Optional i As Long, Optional s As Boolean)'第一个参数rng 为数据源'第二个参数str 为正则表达式'第三个参数i 为正则表达式成功匹配的结果列表中的第几个,从0开始,默认为0即第1个'第四个参数s 为文本[True]或数字[False],用于剔除数字中的文本内容,默认为数字[False]If IsMissing(i) Then i = 0If IsMissing(s) Then s = FalseDim iRg As ObjectSet iRg = CreateObject("VBscript.regexp")With iRg.Global = True.Pattern = str '表达式,直接从用户函数的第二个参数中调用If .Execute(rng).Count = 0 Then'如果匹配到结果的量为0则GetStr = ""'返回结果为空值'函数结束ElseIf IsNumeric(.Execute(rng)(i)) Or s Then'如果第一次得到的结果是数字或者函数的第4个参数为True或非0则GetStr = .Execute(rng)(i)'直接返回第一次得到的结果'函数结束ElseGetStr = GetStr(.Execute(rng)(i), "[0-9]+[.]{0,1}[0-9]{0,}")'否则从第一次返回的结果中剔除数字以外的字符'即调用函数本身再传入一个数字的正则表达式"[0-9]+[.]{0,1}[0-9]{0,}"End IfEnd IfEnd WithEnd Function
测试结果:
B | C | D | E | F | |
2 | 源文本.1 | ss11.11cmcxzas/.'22.22cmwq.,3cmd.,/;eq4.44444cm | |||
3 | 正则表达式.1 | [0-9]+[.]{0,}[0-9]{0,}[cm] | |||
4 | 第3参数(i) 第4参数(s) |
0 | 1 | 2 | 3 |
5 | |||||
6 | 0 | 11.11 =GetStr(C2,C3,C4,B6) | 22.22 =GetStr(C2,C3,D4,B6) | 3 =GetStr(C2,C3,E4,B6) | 4.44444 =GetStr(C2,C3,F4,B6) |
7 | 1 | 11.11c =GetStr(C2,C3,C4,B7) | 22.22c =GetStr(C2,C3,D4,B7) | 3c =GetStr(C2,C3,E4,B7) | 4.44444c =GetStr(C2,C3,F4,B7) |
8 | |||||
9 | 源文本.2 | ss11.11cmcmxzas/.'22.22cmwq.,333333cmd.,/;eq4.44444cm | |||
10 | 正则表达式.2 | [0-9]+[.]{0,}[0-9]{0,}[cm]+ | |||
11 | 第3参数(i) 第4参数(s) |
0 | 1 | 2 | 3 |
12 | |||||
13 | 0 | 11.11 =GetStr(C9,C10,C11,B13) | 22.22 =GetStr(C9,C10,D11,B13) | 333333 =GetStr(C9,C10,E11,B13) | 333333cm =GetStr(C9,C10,E11,B14) |
14 | 1 | 11.11cmcm =GetStr(C9,C10,C11,B14) | 22.22cm =GetStr(C9,C10,D11,B14) | 333333cm =GetStr(C9,C10,E11,B14) | 4.44444cm =GetStr(C9,C10,F11,B14) |
分析:
我们从[C6]单元格开始说起
代入目标单元格解析的公式是:
=GetStr("ss11.11cmcxzas/.'22.22cmwq.,3cmd.,/;eq4.44444cm","[0-9]+[.]{0,}[0-9]{0,}[cm]",0,0)
调式:
在第17行代码添加断点,然后在监视窗口中添加监视:
irg.Execute(Rng)
双击[C6]单元格,回车就可以看到如下图所示
可以看到这个 "[0-9]+[.]{0,}[0-9]{0,}[cm]" 正则表达式作用在这段"ss11.11cmcxzas/.'22.22cmwq.,3cmd.,/;eq4.44444cm"文字中,会得到4个结果,那么就可以通过传入第3个参数 i 来选择我们想要的第几个结果。
在[C6]单元格中我们第三个参数是0,也是就返回匹配到的第0个结果,11.11c
细心一点会发现两个问题:
传入的正则表达式是 "[0-9]+[.]{0,}[0-9]{0,}[cm]",末尾是 cm 为啥只匹配到了c
【C6】单元格的结果是11.11
一个一个的来解答
第1个问题是因为[cm]默认只匹配中括号中的第一个符号,也就是c,如果想要匹配[cm]有几种方法
笨方法:[c][m]或者[cm]{2}或者[cm]{0,}
好方法:[cm]+或者cm
第2个问题是因为一般匹配的数字的时候,数字后面可能会有一些特定字符比如单位。而匹配的结果会把这些字符一起放进去,这样就不方便使用公式进行计算或者统计总数,需要二次匹配,也就是在得到一个包含字符的数字中剔除字符,只保留数字。
关键就在24-33行代码:
If IsNumeric(.Execute(rng)(i)) Or s Then'如果第一次得到的结果是数字或者函数的第4个参数为True或非0则GetStr = .Execute(rng)(i)'直接返回第一次得到的结果ElseGetStr = GetStr(.Execute(rng)(i), "[0-9]+[.]{0,1}[0-9]{0,}")'否则从第一次返回的结果中剔除数字以外的字符'即调用函数本身再传入一个数字的正则表达式"[0-9]+[.]{0,1}[0-9]{0,}"End If
根据这个思路看测试结果,就很清晰明了了。