Sub Analyse_SumProduct_DONKEYOTE()
'-------------------------------------------------------------------------------------------------------------------------
'coded (poorly) by DonkeyOte Weds 22 Oct 2008
'abbreviations
'SP - SumProduct
'SPA - SumProduct Analysis
'-------------------------------------------------------------------------------------------------------------------------
'#DEFINE VARIABLES (Assign/Set where possible)
'-------------------------------------------------------------------------------------------------------------------------
Dim s_s1 As String: s_s1 = ActiveSheet.Name 'to hold sheet name on which SP formula resides
Dim s_s2 As String 'to hold sheet name of SPA sheet (to be created)
Dim s_c1 As String: s_c1 = ActiveCell.Address(0, 0) 'to hold cell address in which SP formula resides
Dim s_c1_f As String: s_c1_f = ActiveCell.formula 'to hold SP formula being analysed
Dim s_c1_f_res As Long 'to hold result of SP formula being analysed
Dim i_c1_f_i As Long 'to hold mid char point when iterating formula string
Dim i_c1_p_cnt As Long 'to hold running total of parentheses
Dim i_c1_f_start As Long 'to hold start char pos of SP component
Dim s_c1_f_delim As String: s_c1_f_delim = "," 'to hold SP component delimiter (eg "," or "*") - change to InputBox later
Dim i_c1_f_c As Integer 'to hold count of "components" within SP formula
Dim l_c1_f_comp_i As Long 'incremental column flag of component parts
Dim s_c1_f_comp As String 'component part of formula as stored in row 5 on SPA sheet
Dim v_c1_f_output 'used to store result of component part
'-------------------------------------------------------------------------------------------------------------------------
'#SET APP SETTINGS
'-------------------------------------------------------------------------------------------------------------------------
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
'-------------------------------------------------------------------------------------------------------------------------
'#STEP 1: VALIDATE FORMULA BEING ANALYSED -- EXIT IF INAPPROPRIATE FOR THIS ROUTINE
'-------------------------------------------------------------------------------------------------------------------------
On Error Resume Next
s_c1_f_res = Evaluate(s_c1_f)
e = Err.Number
On Error GoTo 0
If InStr(UCase(s_c1_f), "=SUMPRODUCT") = 0 Then e = 1 'although formula is valid it's not a SUMPRODUCT formula!
If InStr(s_s1, "SPA") Then e = 1 'firing code from previously created SPA sheet!
'exit routine if formula not valid for analysis
If e <> 0 Then
MsgBox "Current Formula Not Valid for SUMPRODUCT Analysis"
GoTo ExitHere:
End If
'-------------------------------------------------------------------------------------------------------------------------
'#STEP 2: INSERT A NEW SHEET ON WHICH THE SPA WILL BE HELD
'set name convention to utilise system time so as to remove possibility of duplication without need for ws testing / deletion
'set up headers and format column A width
'-------------------------------------------------------------------------------------------------------------------------
Sheets.Add
ActiveSheet.Name = "SPA_" & Format(Now(), "DDMMYY_HHMMSS")
s_s2 = ActiveSheet.Name
Cells(1, 1) = "Formula Location:"
Cells(1, 2) = s_s1 & "!" & s_c1
Cells(2, 1) = "Formula: "
Cells(2, 2) = "'" & s_c1_f
Cells(3, 1) = "Result: "
Cells(3, 2) = s_c1_f_res
Cells(5, 1) = "Component Part(s):"
Cells(7, 1) = "Row/Column:"
Cells(7, 2) = "Result:"
'-------------------------------------------------------------------------------------------------------------------------
'#STEP 3: BEGINNING STRIPPING DOWN FORMULA INTO "COMPONENT" PARTS
'first remove =SUMPRODUCT() leaving just innards behind...
'loop the remaining string using predefined component "delimiter" (eg "," or "*") to break into parts (check parentheses)
'-------------------------------------------------------------------------------------------------------------------------
s_c1_f = Replace(s_c1_f, "=SUMPRODUCT(", "")
s_c1_f = Left(s_c1_f, Len(s_c1_f) - 1)
'default start pos of string to be 1
i_c1_f_start = 1
'iterate formula string
For i_c1_f_i = i_c1_f_start To Len(s_c1_f) Step 1
'ascertain current character and act appropriately
Select Case Mid(s_c1_f, i_c1_f_i, 1)
Case "("
'opening parentheses so add 1 to parentheses count
i_c1_f_p_cnt = i_c1_f_p_cnt + 1
Case ")"
'closing parentheses so remove 1 from parentheses count
i_c1_f_p_cnt = i_c1_f_p_cnt - 1
Case s_c1_f_delim
'current char appears to be delimiter however only valid end point IF count of parentheses is 0
If i_c1_f_p_cnt = 0 Then
'increment count of components
i_c1_f_c = i_c1_f_c + 1
'paste formula component as header in column B onwards (row 5)
Cells(5, 1 + i_c1_f_c) = Mid(s_c1_f, i_c1_f_start, i_c1_f_i - i_c1_f_start)
'reset start pos to be current string pos + 1
i_c1_f_start = i_c1_f_i + 1
End If
End Select
Next i_c1_f_i
'insert final component
'increment count of components
i_c1_f_c = i_c1_f_c + 1
'paste formula component as header in column B onwards (row 5)
Cells(5, 1 + i_c1_f_c) = Mid(s_c1_f, i_c1_f_start, i_c1_f_i - 1)
'-------------------------------------------------------------------------------------------------------------------------
'#STEP 4: EVALUATE EACH COMPONENT PART & WRITE BACK RESULTS TO SPA SHEET (add total column)
'return to parent sheet such that correct relative range references are used prior to evaluation
'-------------------------------------------------------------------------------------------------------------------------
Sheets(s_s1).Select
For l_c1_f_comp_i = 2 To Sheets(s_s2).Cells(5, Columns.Count).End(xlToLeft).Column Step 1
s_c1_f_comp = Sheets(s_s2).Cells(5, l_c1_f_comp_i)
v_c1_f_output = Application.Evaluate(s_c1_f_comp)
Sheets(s_s2).Cells(8, l_c1_f_comp_i).Resize(UBound(v_c1_f_output)).Value = v_c1_f_output
Next l_c1_f_comp_i
Sheets(s_s2).Select
Cells(5, Columns.Count).End(xlToLeft).Offset(2, 1).Value = "Total(s)"
Cells(8, l_c1_f_comp_i).Resize(UBound(v_c1_f_output)).FormulaR1C1 = "=PRODUCT(RC2:RC[-1])"
Cells(8, l_c1_f_comp_i).Resize(UBound(v_c1_f_output)).formula = Cells(8, l_c1_f_comp_i).Resize(UBound(v_c1_f_output)).Value
Cells(8, l_c1_f_comp_i).Resize(UBound(v_c1_f_output)).Font.Bold = True
'-------------------------------------------------------------------------------------------------------------------------
'#STEP 5: FORMAT SPA SHEET
'-------------------------------------------------------------------------------------------------------------------------
Columns(1).AutoFit
Range(Cells(5, 2), Cells(5, 2).End(xlToRight)).Columns.AutoFit
'-------------------------------------------------------------------------------------------------------------------------
'#EXIT POINT
'-------------------------------------------------------------------------------------------------------------------------
ExitHere:
'-------------------------------------------------------------------------------------------------------------------------
'#RESET APP SETTINGS
'-------------------------------------------------------------------------------------------------------------------------
With Application
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
'-------------------------------------------------------------------------------------------------------------------------
'#END
'-------------------------------------------------------------------------------------------------------------------------
End Sub