Split Me, Shape Me
4 October 2011 1 Comment
in which we publish something we wrote a while back but forgot to post for reasons now lost in the mists of time
While I’d love to be able to take credit for having thought of this myself, the truth is I can’t. I did clean up the code a fair bit, though, so any tidiness that particularly appeals is entirely down to me.
Reading this post a while back, I leapt to post my CellSplit() function in the comments, then realised that I typically use it in conjunction with a rather more substantial macro, one that wasn’t going to sit well in someone else’s blog comments.
Here’s my CellSplit(), which is just a wrapper for the VBA Split() function:
Public Function CellSplit(celValue As String, delim As String) As Variant
CellSplit = Split(celValue, delim)
End Function
On its own, it’s moderately useful, but unless you know how many parts your input string will split into, you’re going to be fooling about with range resizing. In these dark days there’s no time for fooling about – we need a tool to get that resizing down for us in One Click.
Enter a toolbar (sorry, RibbonX) button, assigned to the Range Resize Wizard…
Public Sub RangeResizeWizard()
Dim result As Variant
Dim fmla As String
Dim rng As range
Dim targetRows As Long
Dim targetCols As Long
On Error GoTo Catch
Set rng = Selection
If IsEmpty(rng) Then Exit Sub
If rng.HasArray Then
Set rng = rng.CurrentArray
fmla = rng.FormulaArray
ElseIf rng.rows.Count = 1 And rng.Columns.Count = 1 Then
fmla = rng.Formula
Else
Exit Sub
End If
result = Evaluate(fmla)
With rng
.ClearContents
If IsArray(result) Then
If NumberOfDimensions(result) = 2 Then
targetRows = UBound(result, 1) - LBound(result, 1) + 1
targetCols = UBound(result, 2) - LBound(result, 2) + 1
Else
targetRows = 1
targetCols = UBound(result, 1) - LBound(result, 1) + 1
End If
On Error GoTo RestoreFormula:
.Resize(targetRows, targetCols).FormulaArray = fmla
On Error GoTo Catch
Else
.Formula = fmla
End If
End With
Finally:
On Error GoTo 0
Exit Sub
Catch:
Debug.Print Err.Description
Resume Finally
RestoreFormula:
Debug.Print Err.Description
rng.FormulaArray = fmla
Resume Finally
End Sub
Function NumberOfDimensions(arr As Variant)
Dim dimensions As Long
Dim junk As Long
On Error GoTo FinalDimension
For dimensions = 1 To 60000
junk = LBound(arr, dimensions)
Next
Exit Function
FinalDimension:
NumberOfDimensions = dimensions - 1
End Function
Note that the array formula in question will be re-evaluated twice, once to determine the dimensions of the output array and again when the formula is pushed back into the new, perfectly-sized range. Further, the routine assumes you haven’t left anything important lying around where it can get overwritten. So it’s to be used with care, but if you spend much time with array formula, you’ll probably find it as useful as I do (if you haven’t already written it yourself).
Note further that it’s not really a “wizard” in the programming sense, in that it doesn’t do any of that walking-you-through-steps thing. It’s just a bit magic.



I’ve jusr read this code again, you’ve implemented an VBA version of catch! , you clever thing you!!! Why did I not see this first time round?!?!