Печать с использованием последовательности последовательных и непоследовательных номеров - PullRequest
0 голосов
/ 01 мая 2020

У меня есть список серийных номеров, которые мне нужно перебрать в макросе. Большинство серийных номеров являются последовательными, но иногда некоторые будут отсутствовать. Например, мне может понадобиться использовать серийные номера 500-510, 512-513, 516.

Есть ли способ l oop через такой список? Я действительно предпочел бы не записывать каждое число, например: 500, 501, 502, 503 ... потому что иногда у меня могут быть сотни серийных номеров.

Кроме того, список будет меняться при каждом запуске, поэтому мне нужно иметь возможность запросить у пользователя список серийных номеров, а затем вставить этот список в макрос vba. Не уверен, как это сделать.

Спасибо.

Ответы [ 3 ]

1 голос
/ 01 мая 2020

Если это не намного сложнее, чем ваша примерная строка, можно сослаться на объект 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, но также и о потенциальных числах, не представленных в строках на листе.

Может быть, немного больше solid будет:

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 оператор или лучше, регулярные выражения.

0 голосов
/ 01 мая 2020

Получить массив чисел в разных последовательностях

В дополнение к правильному ответу 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

Методические подсказки

Чтобы избежать различия между отдельными числами и диапазоном номеров, я изменил любой числовой токен на пара чисел путем повторного добавления того же самого токена (с префиксом "-") к себе, что упрощает разбиение и возможное назначение l oop.

Таким образом, разделение последнего токена "516-516" позволит собрать соответствующий элемент массива за один шаг l oop, тогда как дополнительное приложение не имеет значения в реальных парах чисел (как разделение избыточного строка "500-510-500-510" приводит к правильным значениям pair(0) = 500 и pair(1) = 510 тоже).

0 голосов
/ 01 мая 2020

Вам понадобится функция, которая принимает строку, такую ​​как "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 
...