【问题标题】:Print Using Sequence of Consecutive and Non-Consecutive Numbers使用连续和非连续数字序列打印
【发布时间】:2020-05-01 11:54:34
【问题描述】:

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

有没有办法循环遍历这样的列表?我真的不想写出每个数字,例如:500、501、502、503……因为有时我可能有数百个序列号。

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

谢谢。

【问题讨论】:

  • 请勾选绿色复选标记,从此处的三个有效解决方案中随意接受有用的答案;了解哪种方法最适合您的需求也可以帮助其他用户:-)

标签: excel vba loops sequence user-input


【解决方案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 运算符或更好的正则表达式。

【讨论】:

  • 很好的答案;仅供参考,发布了另一种将数字分配给数组 +)
【解决方案2】:

您需要一个函数,该函数接受 "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 

【讨论】:

    【解决方案3】:

    获取不同序列的数字数组

    除了 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" 将允许在单个循环步骤中收集相关的数组项,而附加的附录在实际的数字对中无关紧要(因为拆分冗余字符串 "500-510-500-510" 会导致一个正确的值pair(0) = 500 和pair(1)=510,也是)。

    【讨论】:

      猜你喜欢
      • 2016-01-10
      • 1970-01-01
      • 2020-11-15
      • 1970-01-01
      • 1970-01-01
      • 2014-08-05
      • 2019-12-01
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多