Страницы: 1
RSS
"Сортировка от А до Я" не "работает", Точнее работает только по какому-то определенному количеству первых символов в ячейке
 
Добрый день, гуру экселя и любители как я!
Столкнулся с такой проблемой - сортирую значения по столбцу А, а они не сортируются. Ущипнул себя, вроде не сплю. Опять сортирую - тоже самое. Файл прикладываю. Отсортированный диапозон должен выглядеть так, как если мы его отсортируем по столбцу С.
Даже не знаю что спросить. И долго мне с этой фобией жить? У всех так или у меня эксель уникальный?
 
Сортировка тестов длиной более 255 символов (planetaexcel.ru)
Это?
 
Нет, это что-то другое. В общем сортировка (по крайней мере у меня) сортирует по первым 255 символам. Если они одинаковые, а за ними находятся разные символы, то эти ячейки никак не отсортировать (штатной сортировкой).
 
Разбейте с помощью ПСТР() на 4 столбца, и сортируйте.
 
Отличное решение, попробую. Нужно разбивать тогда по 255 символов в ячейку и сортировать столбцы поочереди. Спасибо МатросНаЗебре!
 
dim284, в VBA можно отсортировать 2D-массив без таких ограничений.
Взять данные с листа в память, отсортировать, выгрузить обратно.
Изменено: Jack Famous - 15.04.2024 17:14:43
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Даже так! Интересненько, а можно попросить кого-нибудь макрос такой написать. Уверен, что не одному мне пригодиться.
 
Выделите диапазон, запустите макрос.
Код
Sub LongStringSort()
    Dim rTarg As Range
    Set rTarg = Selection
    Set rTarg = rTarg.Columns(1)
    Set rTarg = Intersect(rTarg, rTarg.Parent.UsedRange)
    Set rTarg = rTarg.Areas(1)
    If rTarg.Cells.CountLarge = 1 Then Exit Sub
    
    Dim arr As Variant
    arr = rTarg.Value
    ClearArray arr
    arr = GetSortArray(arr)
    If IsEmpty(arr) Then Exit Sub
    rTarg.Value = arr
End Sub

Private Function GetSortArray(arr As Variant) As Variant
    Dim mrr As Variant
    mrr = GetMultiColumnArray(arr)
    If IsEmpty(mrr) Then Exit Function
    
    With Workbooks.Add(1)
        With .Sheets(1)
            Dim rr As Range
            Set rr = .Cells(1, 1).Resize(UBound(mrr, 1), UBound(mrr, 2))
            rr.Value = mrr
            With .Sort
                .SortFields.Clear
                Dim xr As Long
                For xr = 1 To rr.Columns.Count
                    .SortFields.Add Key:=rr.Columns(xr), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
                Next
                .SetRange rr
                .Header = xlGuess
                .MatchCase = False
                .Orientation = xlTopToBottom
                .SortMethod = xlPinYin
                .Apply
            End With
            mrr = rr.Value
        End With
        .Close False
    End With
    
    Dim orr As Variant
    orr = GetOneColumnArray(mrr)
    
    GetSortArray = orr
End Function

Private Function GetOneColumnArray(arr As Variant) As Variant
     Dim orr As Variant
     ReDim orr(1 To UBound(arr, 1), 1 To 1)
     
     Dim ya As Long
     Dim xa As Long
     Dim ss As String
     For ya = 1 To UBound(arr, 1)
        ss = ""
        For xa = 1 To UBound(arr, 2)
            ss = ss & arr(ya, xa)
        Next
        orr(ya, 1) = ss
     Next
     
     GetOneColumnArray = orr
End Function

Private Function GetMultiColumnArray(arr As Variant) As Variant
    Const nStep = 255

    Dim nx As Long
    nx = GetColumnNumbers(arr, nStep)
    If nx = 0 Then Exit Function
    
    Dim brr As Variant
    ReDim brr(1 To UBound(arr, 1), 1 To nx)
    
    Dim ss As String
    Dim xb As Long
    Dim ya As Long
    For ya = 1 To UBound(arr, 1)
         If arr(ya, 1) <> "" Then
            xb = 1
            Do
                ss = Mid(arr(ya, 1), 1 + (xb - 1) * nStep, nStep)
                If ss = "" Then Exit Do
                brr(ya, xb) = ss
                xb = xb + 1
            Loop
         End If
    Next
    
    GetMultiColumnArray = brr
End Function

Private Function GetColumnNumbers(arr As Variant, nn As Long) As Long
    Dim ni As Long
    Dim nMax As Long
    Dim ya As Long
    For ya = 1 To UBound(arr, 1)
        If arr(ya, 1) <> "" Then
            ni = Len(arr(ya, 1)) \ nn + 1
            If nMax < ni Then nMax = ni
        End If
    Next
    GetColumnNumbers = nMax
End Function

Private Sub ClearArray(arr As Variant)
    Dim ya As Long
    Dim xa As Long
    For ya = LBound(arr, 1) To UBound(arr, 1)
        For xa = LBound(arr, 2) To UBound(arr, 2)
            If IsError(arr(ya, xa)) Then
                arr(ya, xa) = Empty
            End If
        Next
    Next
End Sub
 
TestSelection сортирует выделенный диапазон по 1му столбцу на месте
Изменено: Jack Famous - 16.04.2024 11:42:00
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
dim284, А функцией СОРТ пробовали?
=СОРТ(A2:A19)
 
Друзья, в целом, все замечательно, все три варианта работают, спасибо! Но, на практике получается так, что таблица как правило состоит из нескольких столбцов и столбец, по которому нужно отсортировать значения, может быть любой по счету (второй, пятый, седьмой и т.д.). А можно сделать так, чтобы после выделения диапозона (из нескольких столбцов) макрос спрашивал по какому столбцу сортировать?
Был не прав, сорри! Функцией СОРТ во втором аргументе указывается номер столбца по которому можно сортировать диапозон. Правда придется новый лист создавать, чтобы большую таблицу заново воссоздать на новом месте.
Изменено: dim284 - 17.04.2024 10:21:26
 
Цитата
написал:
А можно сделать так, чтобы после выделения диапазона (из нескольких столбцов) макрос спрашивал по какому столбцу сортировать
Код
'v2
Sub LongStringSort()
    Dim rTarg As Range
    Set rTarg = Selection
    'Set rTarg = rTarg.Columns(1)
    Set rTarg = Intersect(rTarg, rTarg.Parent.UsedRange)
    Set rTarg = rTarg.Areas(1)
    If rTarg.Cells.CountLarge = 1 Then Exit Sub
    
    Dim rSort As Range
    On Error Resume Next
    Set rSort = Application.InputBox("Введите столбец сортировки", "Сортировка", rTarg.Columns(1).EntireColumn.Address(0, 0, xlA1), Type:=8)
    On Error GoTo 0
    If rSort Is Nothing Then Exit Sub
    If Intersect(rSort, rTarg) Is Nothing Then Exit Sub
    
    Dim xSort As Long
    xSort = rSort.Column - rTarg.Column + 1
    If xSort < 0 Then Exit Sub
    
    Dim arr As Variant
    arr = rTarg.Value
    ClearArray arr
    arr = GetSortArray(arr, xSort)
    If IsEmpty(arr) Then Exit Sub
    rTarg.Value = arr
End Sub

Private Function GetSortArray(arr As Variant, xSort As Long) As Variant
    Dim sortBeg As Long
    Dim sortFin As Long
    Dim mrr As Variant
    mrr = GetMultiColumnArray(arr, xSort, sortBeg, sortFin)
    If IsEmpty(mrr) Then Exit Function
    If sortBeg < 1 Then Exit Function
    If sortFin < sortBeg Then Exit Function
    
    With Workbooks.Add(1)
        With .Sheets(1)
            Dim rr As Range
            Set rr = .Cells(1, 1).Resize(UBound(mrr, 1), UBound(mrr, 2))
            rr.Value = mrr
            With .Sort
                .SortFields.Clear
                Dim xr As Long
                For xr = sortBeg To sortFin
                    .SortFields.Add Key:=rr.Columns(xr), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
                Next
                .SetRange rr
                .Header = xlGuess
                .MatchCase = False
                .Orientation = xlTopToBottom
                .SortMethod = xlPinYin
                .Apply
            End With
            mrr = rr.Value
        End With
        .Close False
    End With
    
    Dim orr As Variant
    orr = GetOneColumnArray(mrr, sortBeg, sortFin)
    
    GetSortArray = orr
End Function

Private Function GetOneColumnArray(arr As Variant, sortBeg As Long, sortFin As Long) As Variant
     Dim orr As Variant
     ReDim orr(1 To UBound(arr, 1), 1 To UBound(arr, 2) - (sortFin - sortBeg))
     
     Dim ya As Long
     Dim xa As Long
     Dim xo As Long
     Dim ss As String
     For ya = 1 To UBound(arr, 1)
        For xa = 1 To sortBeg - 1
            orr(ya, xa) = arr(ya, xa)
        Next
        xo = UBound(orr, 2)
        For xa = UBound(arr, 2) To sortFin + 1 Step -1
            orr(ya, xo) = arr(ya, xa)
            xo = xo - 1
        Next
        
        ss = ""
        For xa = sortBeg To sortFin
            ss = ss & arr(ya, xa)
        Next
        orr(ya, sortBeg) = ss
     Next
     
     GetOneColumnArray = orr
End Function

Private Function GetMultiColumnArray(arr As Variant, xSort As Long, sortBeg As Long, sortFin As Long) As Variant
    Const nStep = 255

    Dim nx As Long
    nx = GetColumnNumbers(arr, xSort, nStep)
    If nx = 0 Then Exit Function
    
    sortBeg = xSort
    sortFin = sortBeg + nx - 1
    
    Dim brr As Variant
    ReDim brr(1 To UBound(arr, 1), 1 To UBound(arr, 2) + nx - 1)
    
    Dim ss As String
    Dim iPart As Long
    Dim xb As Long
    Dim xa As Long
    Dim ya As Long
    For ya = 1 To UBound(arr, 1)
        For xb = 1 To xSort - 1
            brr(ya, xb) = arr(ya, xb)
        Next
        
        xb = UBound(brr, 2)
        For xa = UBound(arr, 2) To xSort + 1 Step -1
            brr(ya, xb) = arr(ya, xa)
            xb = xb - 1
        Next

        If arr(ya, xSort) <> "" Then
           xb = xSort
           iPart = 0
           Do
               ss = Mid(arr(ya, xSort), 1 + iPart * nStep, nStep)
               If ss = "" Then Exit Do
               brr(ya, xb) = ss
               xb = xb + 1
               iPart = iPart + 1
           Loop
        End If
    Next
    
    GetMultiColumnArray = brr
End Function

Private Function GetColumnNumbers(arr As Variant, xSort As Long, nn As Long) As Long
    Dim ni As Long
    Dim nMax As Long
    Dim ya As Long
    For ya = 1 To UBound(arr, 1)
        If arr(ya, xSort) <> "" Then
            ni = Len(arr(ya, xSort)) \ nn + 1
            If nMax < ni Then nMax = ni
        End If
    Next
    GetColumnNumbers = nMax
End Function

Private Sub ClearArray(arr As Variant)
    Dim ya As Long
    Dim xa As Long
    For ya = LBound(arr, 1) To UBound(arr, 1)
        For xa = LBound(arr, 2) To UBound(arr, 2)
            If IsError(arr(ya, xa)) Then
                arr(ya, xa) = Empty
            End If
        Next
    Next
End Sub
 
МОДЕРАТОРАМ:
Предложение изменить название темы
"Сортировка строк длиной более 255 символов"
 
Отличный макрос получился, спасибо МатросНаЗебре!
Предложение переименовать название темы на следующее:
"Сортировка строк длиной более 255 символов", или почему "Сортировка от А до Я" не сортирует диапозон (не работает).
Вторая часть нужна потому, что когда возникает проблема, люди в интеренете ищут её решение именно по названию проблемы, а то что "строки длиной более 255 символов" ещё посчитать надо. Боюсь многие до этого не дойдут.
Страницы: 1
Наверх