我有一个需要在宏中循环显示的序列号列表。大多数序列号是连续的,但偶尔会丢失一些。例如,我可能需要使用序列号500-510、512-513、516。
有没有办法遍历这样的列表?我真的希望不必写出每个数字,例如:500、501、502、503 ...因为有时我可以有数百个序列号。
此外,该列表将随每次运行而变化,因此我需要能够向用户询问序列号列表,然后将该列表插入vba宏。不知道该怎么做。
谢谢。
答案 0 :(得分:1)
如果它没有比示例字符串复杂得多,则可以引用Range
对象,例如:
Sub Test()
Dim str As String: str = "500-510,512-513,516"
For Each i In Range("A" & Replace(Replace(str, "-", ":A"), ",", ",A"))
Debug.Print i.Row
Next
End Sub
这种方法显然有局限性(在连接表示Range
的字符串的长度方向上都是有限制的,但是在工作表上没有通过行表示的潜在数字上也有限制。
也许会更加扎实:
Sub Test()
Dim str As String: str = "500-510,512-513,516"
For Each el In Split(str, ",")
If InStr(1, el, "-") > 0 Then
For x = Val(el) To Val(Right(el, InStrRev(el, "-") - 1))
Debug.Print x
Next
Else
Debug.Print Val(el)
End If
Next
End Sub
关于输入字符串验证;您可以研究Like
运算符或更好的正则表达式。
答案 1 :(得分:0)
您将需要一个函数,该函数接受诸如"500-510,512-513,516"
之类的字符串并返回该表达式表示的数字数组。我尚未完全测试以下内容,但似乎可以完成此任务:
Function ParseNonContiguousRange(rangeExpr As String) As Long()
Dim tokens As Variant, token As Variant
Dim rangeStart As Long, rangeEnd As Long, count As Long, i As Long, index As Long
tokens = Split(rangeExpr, ",")
'First pass: count numbers in range
For Each token In tokens
If InStr(token, "-") Then
rangeStart = CLng(Split(token, "-")(0))
rangeEnd = CLng(Split(token, "-")(1))
count = count + rangeEnd - rangeStart
Else
count = count + 1
End If
Next token
Dim result() As Long
ReDim result(count + 1)
'Second pass: populate range
For Each token In tokens
If InStr(token, "-") Then
rangeStart = CLng(Split(token, "-")(0))
rangeEnd = CLng(Split(token, "-")(1))
For i = rangeStart To rangeEnd
result(index) = i
index = index + 1
Next i
Else
result(index) = CLng(token)
index = index + 1
End If
Next token
ParseNonContiguousRange = result
End Function
Sub TestParseNonContiguousRange()
Dim output() As Long
output = ParseNonContiguousRange("500-510,512-513,516")
For Each i In output
Debug.Print i
Next i
End Sub
500
501
502
503
504
505
506
507
508
509
510
512
513
516
答案 2 :(得分:0)
获取不同顺序的数字数组
除了JvDv的有效答案外,还可以使用另一种方法将项目分配给基于0的 1-dim数组,该数组可以用于进一步处理:
Sub GetArrayOfNumbers()
Dim numbers As String: numbers = "500-510,512-513,516"
ReDim tmp(10000) ' provide for enough items in temp array
Dim number
For Each number In Split(numbers, ",") ' check each number or pair of numbers
Dim pair: pair = Split(number & "-" & number, "-")
Dim i As Long, counter As Long
For i = Val(pair(0)) To Val(pair(1))
tmp(counter) = i: counter = counter + 1 ' add number to temporary array
Next
Next number
ReDim Preserve tmp(0 To counter - 1) ' reduce to exact items count
Debug.Print Join(tmp, ",") ' (optional) display in VB Editor's Immediate Window
' ~> 500,501,502,503,504,505,506,507,508,509,510,512,513,516
End Sub
系统提示
为了避免在单个数字和数字范围之间进行区分,我将任何数字令牌更改为一对数字,方法是在其自身上重新添加相同的令牌(以“-”为前缀),从而简化了拆分和最终的分配循环。
因此,拆分最后一个标记"516-516"
将允许在单个循环步骤中收集相关的数组项,而其他附录在实际的数字对中并不重要(因为拆分冗余字符串{{1 }}也会产生正确的值"500-510-500-510"
= 500和pair(0)
= 510)。