使用连续和非连续数字序列打印

时间:2020-05-01 11:54:34

标签: excel vba loops sequence user-input

我有一个需要在宏中循环显示的序列号列表。大多数序列号是连续的,但偶尔会丢失一些。例如,我可能需要使用序列号500-510、512-513、516。

有没有办法遍历这样的列表?我真的希望不必写出每个数字,例如:500、501、502、503 ...因为有时我可以有数百个序列号。

此外,该列表将随每次运行而变化,因此我需要能够向用户询问序列号列表,然后将该列表插入vba宏。不知道该怎么做。

谢谢。

3 个答案:

答案 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)。