实例需求:某业务系统的逻辑公式如下所示(单行文本),保存在活动工作表的A1单元格中。
"DSO_90Day"->"FA_NoFunc"->"FCCS_No Intercompany"->"FCCS_Data Input"->"FCCS_No Movement"->"NoCC"->"FCCS_YTD_Input" = (("TradeAR"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" - "TradeARTooling"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" + "AllowDbtflAcc"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" ) / ("NetSalesTwoMthsPrior"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" + "NetSalesCurrent"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" + "NetSalesPrior"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic")) * 90;
为了便于大家理解数据提取需求,将逻辑公式格式化为缩进格式。
"DSO_90Day"->"FA_NoFunc"->"FCCS_No Intercompany"->"FCCS_Data Input"->"FCCS_No Movement"->"NoCC"->"FCCS_YTD_Input" =
(
("TradeAR"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" -
"TradeARTooling"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" +
"AllowDbtflAcc"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" ) /
("NetSalesTwoMthsPrior"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" +
"NetSalesCurrent"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic" +
"NetSalesPrior"->"Total Functional Area"->"FCCS_Intercompany Top"->"FCCS_Total Data Source"->"FCCS_Movements"->"Total Business Unit"->"FCCS_Periodic")
) *
90;
现在需要按如下规则提取数据,结果如下所示。
- 提取引号之间的的关键字,可能包含空格
- 提取相应的操作符合: + - * / =
- 提取最后的数字
示例代码如下。
Sub ParseRule()
Dim ruleSheet As Worksheet
Dim smartViewSheet As Worksheet
Dim rule As String, res()
Dim i As Long, j As Long, iR As Long
Dim aTxt, strMatch As String, arrRes
Dim objRegExp As Object, objMatch As Object
Set ruleSheet = ThisWorkbook.Sheets(1)
Set smartViewSheet = ThisWorkbook.Sheets(2)
smartViewSheet.Cells.Clear
rule = ruleSheet.Range("A1").Value
Set objRegExp = CreateObject("vbscript.regexp")
objRegExp.Pattern = "((?:[\w ]+->){6}[\w]+)[\s)]*([=+\-*\/])\s([\d]*)"
objRegExp.Global = True
objRegExp.IgnoreCase = True
objRegExp.MultiLine = False
Set objMatch = objRegExp.Execute(Replace(rule, Chr(34), ""))
If objMatch.Count > 0 Then
ReDim arrRes(1 To objMatch.Count + 1, UBound(Split(objMatch(0).submatches(0), "->")) + 2)
For j = 0 To objMatch.Count - 1
strMatch = objMatch(j).submatches(0)
aTxt = Split(strMatch, "->")
iR = iR + 1
For i = 0 To UBound(aTxt)
arrRes(iR, i) = Trim(aTxt(i))
Next
arrRes(iR, i + 1) = objMatch(j).submatches(1)
If Len(objMatch(j).submatches(2)) > 0 Then
arrRes(iR + 1, i + 1) = objMatch(j).submatches(2)
End If
Next
End If
smartViewSheet.Range("A1").Resize(UBound(arrRes, 1), UBound(arrRes, 2) + 1).Value = arrRes
End Sub
【代码解析】
第9~10行代码获取工作表对象。
第11行代码清空工作表用于保存结果。
第12行代码由A1单元格读取字符串。
第13行代码创建正则对象。
第14行代码设置正则匹配模式。
正则表达式 | 说明 |
---|---|
[\w ] | 非提取组用于匹配数字、字母和空格 |
(?:[\w ]+->){6} | 非提取组,用于6匹配关键字(单个或者多个)-> |
((?:[\w ]+->){6}[\w]+) | 之后匹配一个或者多个字符,作为第一个提取组 |
[\s)]* | 匹配任意个数的白字符或者右括号 |
([=+-*/]) | 第二个匹配组,用于提取符号 |
\s | 匹配单个白字符 |
([\d]*) | 第3个匹配组,用于匹配任意数量的数字 |
第15行代码设置正则全局匹配。
第16行代码设置正则匹配忽略大小写。
第16行代码设置正则匹配使用单行模式。
第17行代码执行正则匹配,注意此处使用Replace函数去除了字符串中的双引号。
第19行代码判断匹配成功。
第20行代码创建数组用于保存结果。
第21~32行代码循环提取每个匹配数据。
第22行代码获取第一个匹配组字符串内容。
第23行代码使用->
作为分界符拆分字符串。
第25~27行代码将拆分后的内容保存在数组中。
第28行代码获取第2个匹配组字符串内容。
第29行代码判断是否成功匹配第3个匹配组,如果存在,那么第30行代码将其保存在结果数组中。
第34行代码将结果写入工作表。