VBA之正则表达式(46)-- 解析业务逻辑公式

82 篇文章 6 订阅
51 篇文章 18 订阅

实例需求:某业务系统的逻辑公式如下所示(单行文本),保存在活动工作表的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行代码将结果写入工作表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值