实例需求:数据保存在A列中,需要将其中重复字符分拆后保存在后续的列中,为简化示例代码,只考虑小写英文字符。
这个需求也并不复杂,用VBA代码逐个判断字符和其前后的字符对比,就可以区分每组,高手可以写出递归调用过程。用正则处理这种问题会更简单。
Sub RegExpDemo()
Dim strTxt As String
Dim objRegEx As Object, objMatch As Object
Dim objMH As Object, c As Range
Set objRegEx = CreateObject("vbscript.regexp")
objRegEx.Global = True
objRegEx.Pattern = "([a-z])\1*"
Range("B:AA").ClearContents
For Each c In Range([A1], Cells(Rows.Count, "A").End(xlUp))
strTxt = c.Value
Set objMatch = objRegEx.Execute(strTxt)
If objMatch.Count > 0 Then
col = 2
For Each objMH In objMatch
Cells(c.Row, col) = objMH.Value
col = col + 1
Next
End If
Next
Set objMH = Nothing
Set objMatch = Nothing
Set objRegEx = Nothing
End Sub
【代码解析】
第5行代码使用后期绑定创建正则对象。
第6行代码设置为全局搜索模式。
第7行代码指定正则匹配字符串,([a-z])
用于匹配单个小写英文字符,并提取为第一组,\1*
含义是第一组字符重复0次(也就是只有单个字符的情况)或者多次。
第8和代码清空后续列用于保存结果。
第9行代码第19行代码循环处理工作表中的数据。
第11行执行正则匹配。
如果匹配成功,第14行到第17行代码将匹配结果写入工作表后续列中。
注意第15行代码读取的是objMH.Value,而不是objMH.submatches(0).Value。
似乎这个代码也没有什么神奇的地方,只是匹配模式中使用了匹配组\1
。
接下来才是今天要讲的重点,上面的正则匹配是通用思路,解决问题时,都是去设法提取匹配的字符串,然后在VBA中加工,这个示例需要写入工作表单元格,那么只要拆分成数组,就可以一次性写入单元格区域了,VBA中拆分数组肯定是用Split
函数了。下面的升级版解决方案中用到了正则替换。
Sub RegExpRepDemo()
Dim strTxt As String, arrRes
Dim objRegEx As Object, objMatch As Object
Dim objMH As Object, c As Range
Set objRegEx = CreateObject("vbscript.regexp")
objRegEx.Global = True
objRegEx.Pattern = "([a-z])(?!\1|$)"
Range("B:AA").ClearContents
For Each c In Range([A1], Cells(Rows.Count, "A").End(xlUp))
strTxt = c.Value
arrRes = Split(objRegEx.Replace(strTxt, "$1 "))
Cells(c.Row, 2).Resize(1, UBound(arrRes) + 1).Value = arrRes
Next
Set objMH = Nothing
Set objMatch = Nothing
Set objRegEx = Nothing
End Sub
【代码解析】
与上面代码相同的步骤这里就不再赘述。
匹配模式 | 含义 |
([a-z]) | 匹配单个小写英文字符,并提取为第一组 |
?! | 零宽度否定顺序环视,不消耗字符,只用于环视判断 |
\1 | 第一组匹配字符(一个或者多个) |
$ | 行的结束标识 |
以aaabbccccdeeee
为例看一下正则匹配过程。
游标位置 | 匹配组 | 下一个字符 | 说明 |
0 | a | a | 下一个字符与匹配组相同,不满足正则模式 |
1 | a | a | 下一个字符与匹配组相同,不满足正则模式 |
2 | a | b | 下一个字符与匹配组不同,满足正则模式,将被替换为 |
3 | b | b | 下一个字符与匹配组相同,不满足正则模式 |
4 | b | c | 下一个字符与匹配组不同,满足正则模式,将被替换为 |
… | … | … | 依次处理每个字符 |
13 | e |
| 下一个为字符结束标识,不满足正则模式 |
正则替换之后的字符串为aaa bb cccc d eeee
,注意字符串末尾并不会添加空格,使用Split
拆分为数组,可以直接写入一行单元格内,这波操作比第一个代码更简洁。