Sub LoopingRanges_BruteForce()
Dim lngLoop As Long
For lngLoop = 1 To 23
Debug.Print lngLoop, ;
Next
For lngLoop = 30 To 30
Debug.Print lngLoop, ;
Next
Debug.Print
End Sub
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 30
Sub LoopingRanges_Arrays()
Dim vItem As Variant
Dim lngLoop As Long
For Each vItem In Array(Array(1, 23), Array(30, 30))
For lngLoop = vItem(0) To vItem(1)
Debug.Print lngLoop, ;
Next
Next
Debug.Print
End Sub
We have effectively refactored the code, eliminating the duplicate For...Next loops in our BruteForce example.
Sub LoopingRanges_Split()
Dim vItem As Variant
Dim lngLoop As Long
Dim strRanges() As String
Dim strLowerUpper() As String
Dim lngLow As Long, lngHigh As Long
Const cRange As String = "1..23,30"
strRanges = Split(cRange, ",")
For Each vItem In strRanges
strLowerUpper = Split(CStr(vItem), "..")
'parse each range for the lower and upper values
lngLow = CLng(strLowerUpper(0))
If UBound(strLowerUpper) = 0 Then
'for single value ranges, the upper = lower
lngHigh = lngLow
Else
lngHigh = CLng(strLowerUpper(1))
End If
For lngLoop = lngLow To lngHigh
Debug.Print lngLoop, ;
Next
Next
Debug.Print
End Sub
Sub LoopingRanges_Regex()
Dim lngLoop As Long
Dim lngLow As Long, lngHigh As Long
Const cRange As String = "1..23,30"
Dim oRE As Object, oMatches As Object, oM As Object
Set oRE = CreateObject("vbscript.regexp")
oRE.Global = True
oRE.Pattern = "(\d+)(?:\.\.){0,1}(\d+){0,1}(?:,|$)"
If oRE.test(cRange) Then
Set oMatches = oRE.Execute(cRange)
For Each oM In oMatches
lngLow = CLng(oM.submatches(0))
If IsEmpty(oM.submatches(1)) Then
'for single value ranges, the upper = lower
lngHigh = Val(oM.submatches(0))
Else
lngHigh = Val(oM.submatches(1))
End If
For lngLoop = lngLow To lngHigh
Debug.Print lngLoop, ;
Next
Next
Else
MsgBox "invalid ranges string"
End If
Debug.Print
End Sub
For more information about regular expressions, read Patrick Matthews's introduction to the topic:
Function ReturnRanges_StaticArrays() As Collection
Dim colReturn As New Collection
colReturn.Add Array(1, 23)
colReturn.Add Array(30, 30)
Set ReturnRanges_StaticArrays = colReturn
End Function
I like to test my code as I develop, so here is a routine that uses
Sub Test_ReturnRanges_StaticArrays()
Dim vItem As Variant
For Each vItem In ReturnRanges_StaticArrays
For lngLoop = vItem(0) To vItem(1)
Debug.Print lngLoop, ;
Next
Next
Debug.Print
End Sub
Function ReturnRanges_Arrays(parmRanges As String) As Collection
Dim colReturn As New Collection
Dim vItem As Variant
Dim lngLoop As Long
Dim strRanges() As String
Dim strLowerUpper() As String
Dim lngLow As Long, lngHigh As Long
strRanges = Split(parmRanges, ",")
For Each vItem In strRanges
strLowerUpper = Split(CStr(vItem), "..")
'parse each range for the lower and upper values
lngLow = CLng(Val(strLowerUpper(0)))
If UBound(strLowerUpper) = 0 Then
'for single value ranges, the upper = lower
lngHigh = lngLow
Else
lngHigh = CLng(Val(strLowerUpper(1)))
End If
colReturn.Add Array(lngLow, lngHigh)
Next
Set ReturnRanges_Arrays = colReturn
End Function
Sub testRR()
Dim lngLoop As Long
Dim vItem As Variant
For Each vItem In ReturnRanges_Arrays("1..5,11,28..30,15..19")
For lngLoop = vItem(0) To vItem(1)
Debug.Print lngLoop, ;
Next
Next
Debug.Print
End Sub
Function ReturnRanges_Arrays_VBS(parmRanges)
'VBScript version of ReturnRanges_Arrays
Dim colReturn
Dim vItem
Dim lngLoop
Dim strRanges
Dim strLowerUpper
Dim lngLow, lngHigh
Set colReturn = CreateObject("scripting.dictionary")
lngLoop = 0
strRanges = Split(CStr(parmRanges), ",")
For Each vItem In strRanges
strLowerUpper = Split(CStr(vItem), "..")
'parse each range for the lower and upper values
lngLow = CLng(Val(strLowerUpper(0)))
If UBound(strLowerUpper) = 0 Then
'for single value ranges, the upper = lower
lngHigh = lngLow
Else
lngHigh = CLng(Val(strLowerUpper(1)))
End If
lngLoop = lngLoop + 1
colReturn.Add CStr(lngLoop), Array(lngLow, lngHigh)
Next
Set ReturnRanges_Arrays_VBS = colReturn
End Function
And our VBScript test code looks like this:
Sub testRR_VBS()
Dim lngLoop
Dim vItem
Dim vRanges
Set vRanges = ReturnRanges_Arrays_VBS("1..5,11,28..30")
For Each vItem In vRanges
For lngLoop = vRanges(vItem)(0) To vRanges(vItem)(1)
Debug.Print lngLoop, ;
Next
Next
Debug.Print
End Sub
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (5)
Commented:
Author
Commented:And consider writing some articles of your own.
Commented:
I've published 23 articles and 10 videos here at EE, and am always considering some new ones. But as you know, it takes a while to write a good article — need to find the time! :)
Author
Commented:Open in new window
Commented: