实例需求:某业务系统的逻辑公式如下所示(单行文本),保存在活动工作表的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 WorksheetDim smartViewSheet As WorksheetDim rule As String, res()Dim i As Long, j As Long, iR As LongDim aTxt, strMatch As String, arrResDim objRegExp As Object, objMatch As ObjectSet ruleSheet = ThisWorkbook.Sheets(1)Set smartViewSheet = ThisWorkbook.Sheets(2)smartViewSheet.Cells.Clearrule = ruleSheet.Range("A1").ValueSet objRegExp = CreateObject("vbscript.regexp")objRegExp.Pattern = "((?:[\w ]+->){6}[\w]+)[\s)]*([=+\-*\/])\s([\d]*)"objRegExp.Global = TrueobjRegExp.IgnoreCase = TrueobjRegExp.MultiLine = FalseSet objMatch = objRegExp.Execute(Replace(rule, Chr(34), ""))If objMatch.Count > 0 ThenReDim arrRes(1 To objMatch.Count + 1, UBound(Split(objMatch(0).submatches(0), "->")) + 2)For j = 0 To objMatch.Count - 1strMatch = objMatch(j).submatches(0)aTxt = Split(strMatch, "->")iR = iR + 1For i = 0 To UBound(aTxt)arrRes(iR, i) = Trim(aTxt(i))NextarrRes(iR, i + 1) = objMatch(j).submatches(1)If Len(objMatch(j).submatches(2)) > 0 ThenarrRes(iR + 1, i + 1) = objMatch(j).submatches(2)End IfNextEnd IfsmartViewSheet.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行代码将结果写入工作表。