Страницы: 1
RSS
Объединение последовательных чисел в числовой период
 
Добрый день.
Помогите, пожалуйста, усовершенствовать макрос сокращения строки последовательных чисел путём объединения значений в числовой период с использованием крайних чисел периода и дефиса
На текущий момент макрос распознает следующую строку с определением префикса "QF":
QF1, QF2, QF3, QF5, QF6, QF7, QF8, QF13, QF14, QF15, QF16, QF17, QF18, QF19, QF21, QF33, QF34
и преобразует её в следующую строку с составлением периодов
QF1-QF3, QF5-QF8, QF13-QF19, QF21, QF33, QF34
Интересует добавление условия распознавания  двух периодов и соединения их в один по двум крайним одинаковых значениям, например:
QF1, QF2, QF3, QF5-QF12, QF13-QF19, QF21
преобразовать в:
QF1-QF3, QF5-QF19, QF21
Буду признателен за помощь.
Код
Function comprsStr(sourceElements As String, Optional prefix As String, Optional separatorCells As String, Optional separatorRngs As String) As String
'Const defaultCellsSep  As String = ", "
Dim defaultCellsSep  As String: defaultCellsSep = ", "
'Const defaultRngsSep As String = "-"
Dim defaultRngsSep  As String: defaultRngsSep = "-"
Dim aElements As Variant
Dim aValues As Variant
Dim i As Long
Dim j As Long
Dim k As Long
Dim n As Long
    comprsStr = "?" ' Результат для ошибочного набора параметров или какой-то ошибки по ходу вычислений
    If IsMissing(separatorCells) Then
        separatorCells = defaultCellsSep
    End If
    If IsMissing(separatorRngs) Then
        separatorRngs = defaultRngsSep
    End If
    aElements = Split(sourceElements, separatorCells)
    If LBound(aElements) = UBound(aElements) Then ' Всего один элемент? Или не правильный сепаратор...
        comprsStr = Trim(sourceElements)
        Exit Function
    End If
    If IsMissing(prefix) Then
        prefix = ""
        For i = 1 To Len(aElements(0))
            If InStr("0123456789", Mid(aElements(0), i, 1)) > 0 Then Exit For
            prefix = prefix + Mid(aElements(0), i, 1)
        Next i
    End If
    ReDim aValues(UBound(aElements))
'    aValues = DimArray(UBound(aElements))
    For i = LBound(aElements) To UBound(aElements)
        aValues(i) = Val(Join(Split(aElements(i), prefix), ""))
    Next i
    Dim aSeries() As Long
    ReDim aSeries(UBound(aElements))
'Dim aSeries(UBound(aElements)) As Long
    n = 1
    aSeries(0) = n
    For i = LBound(aElements) + 1 To UBound(aElements)
        If aValues(i) - aValues(i - 1) <> 1 Then n = n + 1 ' Не просто "больше", а "не равно" - порядок сортировки мы не проверяли
        aSeries(i) = n
    Next i
    If n >= (UBound(aElements) / 2) Then ' Нет ни одной серии больше двух элементов подряд
        comprsStr = Trim(sourceElements)
        Exit Function
    End If
    Dim aCounts() As Long
    ReDim aCounts(n)
'Dim aCounts(n) As Long

    For i = LBound(aElements) To UBound(aElements)
        aCounts(aSeries(i)) = aCounts(aSeries(i)) + 1
    Next i
Rem Собираем данные для результата
Dim aRes() As String
ReDim aRes(UBound(aElements))
'Dim aRes(UBound(aElements)) As String
    i = 0
    j = 0
    For k = 1 To n
        If aCounts(k) = 1 Then
            aRes(j) = aElements(i)
            i = i + 1
            j = j + 1
        ElseIf aCounts(k) = 2 Then
 
Код
Function fComprStr(sStr As String, _
                Optional sPrefix As String = "QF", _
                Optional sSepCells As String = ", ", _
                Optional sSepRng As String = "-") As String
    Dim sTxt As String, aSpl
    Dim lMin As Long, lValueLow As Long, lValueUpp As Long
    Dim j As Long, bFlag As Boolean

    aSpl = Split(Replace(sStr, sPrefix, ""), sSepCells)
    lMin = Val(aSpl(0))
    
    For j = 0 To UBound(aSpl)
        ' определяем границы диапазона
        lValueLow = Val(aSpl(j))
        lValueUpp = Val(Split(aSpl(j) & sSepRng, sSepRng)(1))
        If lValueUpp = 0 Then lValueUpp = lValueLow
        
        If lMin + 1 = lValueLow Then
            lMin = lValueUpp
            bFlag = True ' флаг продолжения диапазона
        Else
            If bFlag = True Then
                sTxt = sTxt & sSepRng & sPrefix & lMin
                bFlag = False
            End If
            
            sTxt = sTxt & sSepCells & sPrefix & lValueLow
            lMin = lValueUpp
            If lValueLow < lValueUpp Then bFlag = True
        End If
    Next j
    
    If bFlag = True Then sTxt = sTxt & sSepRng & sPrefix & lMin
    fComprStr = Mid$(sTxt, Len(sSepCells) + 1)
End Function

Текст QF1, QF2, QF4 отобразится так:  QF1-QF2, QF4
Если не нравится, добавить в двух местах (строки 23, 33) условие проверки получаемого периода (или вынести в отдельную функцию):
если границы рядом, то ставить другой разделитель
 
обратное преобразование есть? периоды в ряд?
То можно сначала в ряд потом в периоды
Как-то был такой вопрос. решал так. Оказалось проще
 
UDF:
Код
Function NumbersPeriod(TXT, d As Long) As String
Dim a&, b&, c&, arr(), dd&(), t$, tt, x&
'------------------------------------------
tt = Split(Replace(Replace(TXT, " ", ""), Left(TXT, d), ""), ",") 'сжигаем пробелы, удаляем символьный префикс, разбиваем по зяпятым
ReDim arr(LBound(tt) To UBound(tt))
For a = LBound(tt) To UBound(tt): arr(a) = CLng(tt(a)): Next 'конвертим текст в числа
ReDim dd(LBound(arr) To UBound(arr)): dd(LBound(dd)) = arr(LBound(arr))
For a = LBound(arr) + 1 To UBound(arr): b = a 'сортируем числа
  Do While dd(b - 1) > arr(a)
    dd(b) = dd(b - 1): b = b - 1
    If b = LBound(arr) Then Exit Do
  Loop: dd(b) = arr(a)
Next: Erase arr
t = Left(TXT, d): b = 0
For a = LBound(dd) To UBound(dd) 'создаем массив с периодами
  c = dd(a): x = 0
  Do While dd(a) - c - x = 0
    a = a + 1: x = x + 1
    If a > UBound(dd) Then Exit Do
  Loop
  a = a - 1: b = b + 1: ReDim Preserve arr(1 To b)
  If x = 1 Then arr(b) = t & c Else arr(b) = t & c & "-" & t & dd(a)
Next
NumbersPeriod = Join(arr, ",") 'объединяем периоды из массива в строку
End Function
 
Спасибо.
Изменено: mensa - 27.03.2019 15:06:09
 
Цитата
написал:
Текст QF1, QF2, QF4 отобразится так:  QF1-QF2, QF4
Добрый день! А что нужно изменить в коде, если в диапазонах просто числа стоят, без префиксов?
Текст 1,2,3,6,7,8 отобразится как: 1-3, 6-8.
Спасибо!
 
Цитата
написал:
Добрый день! А что нужно изменить в коде, если в диапазонах просто числа стоят, без префиксов?Текст 1,2,3,6,7,8 отобразится как: 1-3, 6-8.
На сегодня все подобные вопросы отлично решаются ChatGpt. Рекомендую к нему обращаться. Исходный код у Вас есть
Страницы: 1
Наверх