如何更改我的列排序以对整个 sheet 而不仅仅是列进行排序?

How do I change my column sort to sort the entire sheet not just a column?

我正在使用底部的代码按字母顺序、数字顺序以及以下字母和标点字符 (AB00017C) 对列进行排序。生活在我正在努力的单栏sheet上是美好的。只要数据在 A 列中,一切看起来都很棒。

当我移动到具有不止一列的 sheet 时,它简直太丑了!

我花了两天时间才让这种工作发挥作用。它在 A 列的右侧插入 3 个辅助列,将 A 列中的单元格值切片到三个新列中,然后按正确顺序对它们进行排序。最后它删除了 3 个辅助列。

我已将代码附加到一个简单的命令按钮以进行测试。抱歉所有评论都被论坛删了

我有 sheet 到 CG 列,这个子例程对它很有帮助。

现在我的头很痛,我想我把自己编程到一个角落里,我不知道怎么出去。

任何见解都将受到热烈欢迎,CraigMc

下面是一些数据


sku         post_title
AB00017a    Lixit, Glass Water Bottle, 32 oz.
AB00017     Lixit, Glass Water Bottle, 16 oz.
AB00016z    Hookbill Legume Blend with Peantus, 32 lbs.
AB00016-b   Bonito Loco Pretty Crazy Nut Blend, 32 lbs. 
AB00016     Madagascar Delite, 64 oz.
AB00017c    Nutmeats and Fruit, 32 lbs. 
AB00017g    Nutmeats and Fruit, 25 oz.

代码如下:


Private Sub CommandButton1_Click()

    Dim intLoops    As Integer

    Dim lngNumeric  As Long
    Dim lngLastRow  As Long

    Dim rngRows     As Range
    Dim rngcell     As Range

    Dim strAlpha    As String
    Dim strPrefix   As String

    Dim strSuffix As String

    '-----------------------------
    strPrefix = "True"

    strSuffix = "False"
    '-----------------------------

    Columns("B:D").Insert Shift:=xlToRight                                      'Insert 3 temporary columns to the Right of Column A.

    lngLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, Left("A1", 1)).End(xlUp).Row

    Set rngRows = Range("A2", Range("A" & Rows.Count).End(xlUp))                'Separates Alpha to Next Column, Numeric to the following column
        For Each rngcell In rngRows
            intLoops = Len(rngcell)                                                 'Works on one character at at time.

                For intLoops = 1 To intLoops                                    'Read each character in the cell

                    If strPrefix = "True" Then

                        If Not IsNumeric(Mid(rngcell, intLoops, 1)) Then            'This is the PREFIX

                            strAlpha = strAlpha & Mid(rngcell, intLoops, 1)

                            If IsNumeric(Mid(rngcell, intLoops + 1, 1)) Then        'Is the next character Aphabetic, Yes this is the SUFFIX coming up.

                                strPrefix = "False"                             'Next Charater is the Suffix
                            End If

                        Else
                            lngNumeric = lngNumeric & Mid(rngcell, intLoops, 1)                   'No it is the number in the middle

                         End If

                    Else                                                        'This is the Suffix

                        If IsNumeric(Mid(rngcell, intLoops, 1)) And strSuffix = "False" Then

                            lngNumeric = lngNumeric & Mid(rngcell, intLoops, 1)                   'No it is the number in the middle

                            If (Mid(rngcell, intLoops + 1, 1)) = "-" Then           'Onceyou hit a non-numeric character stay in the suffix.

                                strSuffix = "True"                              'Ensures that all that follows the center number stays in the Suffix.

                            End If

                        Else

                            alpSuffix = alpSuffix & Mid(rngcell, intLoops, 1)       'Character SUFFIX

                        End If

                    End If

                Next intLoops

            rngcell.Offset(, 1) = strAlpha
            rngcell.Offset(, 2) = lngNumeric
            rngcell.Offset(, 3) = alpSuffix & " "
            strAlpha = vbNullString
            lngNumeric = 0
            alpSuffix = vbNullString
            strPrefix = "True"
            strSuffix = "False"
        Next rngcell
    Set rngRows = rngRows.Resize(rngRows.Rows.Count, 4)

    rngRows.Sort key1:=rngRows.Range(Cells(1, 3), Cells(rngRows.Rows.Count, 3)), order1:=xlAscending, _
                 key2:=rngRows.Range(Cells(1, 2), Cells(rngRows.Rows.Count, 2)), order2:=xlAscending, Header:=xlGuess

    lngLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, Left("A2", 1)).End(xlUp).Row

    ActiveSheet.Sort.SortFields.Clear
    ActiveSheet.Sort.SortFields.Add Range("B1"), xlSortOnValues, xlAscending
    ActiveSheet.Sort.SortFields.Add Range("C1"), xlSortOnValues, xlAscending
    ActiveSheet.Sort.SortFields.Add Range("D1"), xlSortOnValues, xlAscending

    With ActiveSheet.Sort
        .SetRange Range("A1").CurrentRegion
        .Header = xlYes
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

    Columns("B:D").Delete Shift:=xlToLeft                                       'Delete the 3 temporary columns to the Right of Column A.

End Sub

谢谢!

我做了一些更改来解决范围问题,但字符串的解析效果很好

我的改动:

  • 我把主程序移到了一个新模块
  • 我改成排序sheet"Master of Masters"具体
  • 重命名了大部分变量,使其更加直观

  • 将与 sheet 对象的交互减少

    • 正在将数据复制到内存,一次
    • 正在使用您的算法解析字符串

      • 但拆分字符串是在内存中完成的,而不是单元格和范围 - 提高了性能
    • 将内存中的数据放回sheet,一次

  • 正在对 sheet 上的所有数据应用排序(您的排序区域设置不当)

  • 删除临时帮助列

.

这是更新后的代码,请放在新模块中


Option Explicit

'Place the code in a new module (from the menu: Insert -> Module)

Private Const START_COL As Byte = 1

Public Sub SortSheet(ByVal wsName As String, _
                     Optional ByVal sortCol As Long = 1, _
                     Optional ByVal row1 As Long = 2)

    Dim wb          As Workbook:    Dim ws          As Worksheet

    Dim lRow        As Long:        Dim lCol        As Long
    Dim thisRow     As Long:        Dim thisStr     As String
    Dim lastCell    As Range

    Dim sortRng     As Range:       Dim sortKey1    As Range
    Dim sortKey2    As Range:       Dim sortKey3    As Range

    Dim memArr1Col  As Variant      'column with strings         (in memory)
    Dim memArr3Col  As Variant      'helper columns, for sorting (in memory)

    Dim char        As Long:        Dim strLen      As Long
    Dim preBol      As Boolean:     Dim sufBol      As Boolean
    Dim midNum      As String
    Dim preStr      As String:      Dim sufStr      As String

    '---------------------------------------
    preBol = True
    sufBol = False
    '---------------------------------------
    With Application
        .ScreenUpdating = False
        Set wb = .ActiveWorkbook
    End With

    Set ws = Sheets(wsName)
    Set lastCell = GetMaxCell(ws.UsedRange)
    lRow = lastCell.Row
    lCol = lastCell.Column

    If row1 <= lRow Then

        With ws                             'set mem arrays: sort col, and helpers
            memArr1Col = .Range(.Cells(row1, sortCol), .Cells(lRow, sortCol))
            memArr3Col = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 3))
        End With

        For thisRow = row1 - 1 To lRow - 1  'parse each cell in sort column

            If Not IsEmpty(memArr1Col(thisRow, 1)) And _
               Not IsNull(memArr1Col(thisRow, 1)) And _
               Len(memArr1Col(thisRow, 1)) > 0 Then

                thisStr = memArr1Col(thisRow, 1)
                strLen = Len(thisStr)

                For char = 1 To strLen          'parse each string
                    If preBol = True Then
                        If Not IsNumeric(Mid(thisStr, char, 1)) Then
                            preStr = preStr & Mid(thisStr, char, 1)
                            preBol = Not IsNumeric(Mid(thisStr, char + 1, 1))
                        Else
                            midNum = midNum & Mid(thisStr, char, 1)
                        End If
                    Else
                        If IsNumeric(Mid(thisStr, char, 1)) And sufBol = False Then
                            midNum = midNum & Mid(thisStr, char, 1)
                            sufBol = (Mid(thisStr, char + 1, 1)) = "-"
                        Else
                            sufStr = sufStr & Mid(thisStr, char, 1)
                        End If
                    End If
                Next   'Next character in the string
                memArr3Col(thisRow, 1) = preStr
                memArr3Col(thisRow, 2) = midNum
                memArr3Col(thisRow, 3) = sufStr & " "
                preBol = True
                sufBol = False
                midNum = vbNullString
                preStr = vbNullString
                sufStr = vbNullString
            End If
        Next   'Next Row

        With ws
            'place helper column values from memory to current worksheet
            .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 3)) = memArr3Col
            'set sort range - all data on this sheet plus the last 3 helper columns
            Set sortRng = .Range(.Cells(row1, START_COL), .Cells(lRow, lCol + 3))

            'set sort keys to helper columns
            Set sortKey1 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))
            Set sortKey2 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))
            Set sortKey3 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))
        End With

        With ws
            With .Sort  'apply the sort
                With .SortFields
                    .Clear
                    .Add sortKey1, xlSortOnValues, xlAscending
                    .Add sortKey2, xlSortOnValues, xlAscending
                    .Add sortKey3, xlSortOnValues, xlAscending
                End With
                .SetRange sortRng
                .Header = xlYes
                .Orientation = xlTopToBottom
                .Apply
            End With
            .Range( _
                    .Cells(row1, lCol + 1), _
                    .Cells(lRow, lCol + 3)).EntireColumn.Delete 'delete helper cols
            .Activate
            .Cells(1, 1).Activate
        End With
    End If
    Application.ScreenUpdating = True
End Sub

.

将这个函数放在同一个(新)模块中


Public Function GetMaxCell(Optional ByRef rng As Range = Nothing) As Range

    'Returns the last cell of range with data, or A1 if Worksheet is empty

    Const NONEMPTY As String = "*"
    Dim lRow As Range, lCol As Range

    If rng Is Nothing Then Set rng = Application.ActiveWorkbook.ActiveSheet.UsedRange
    If WorksheetFunction.CountA(rng) = 0 Then
        Set GetMaxCell = rng.Parent.Cells(1, 1)
    Else
        With rng
            Set lRow = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
                                   After:=.Cells(1, 1), _
                                   SearchDirection:=xlPrevious, _
                                   SearchOrder:=xlByRows)
            If Not lRow Is Nothing Then
                Set lCol = .Cells.Find(What:=NONEMPTY, LookIn:=xlFormulas, _
                                       After:=.Cells(1, 1), _
                                       SearchDirection:=xlPrevious, _
                                       SearchOrder:=xlByColumns)

                Set GetMaxCell = .Parent.Cells(lRow.Row, lCol.Column)
            End If
        End With
    End If
End Function

.

您可以从任何 Sheet 模块调用主函数,如下所示:


Option Explicit

Private Sub CommandButton1_Click()

    SortSheet wsName:="Master of Masters"

End Sub

或者像这样(覆盖默认参数)


Option Explicit

Private Sub CommandButton1_Click()

    SortSheet wsName:="Master of Masters", sortCol:=1, row1:=2

End Sub

.

要更改排序键,请相应修改以下 3 行:

这按 PreFix 排序(第一个辅助列,然后是第二列,然后是第三列):

Set sortKey1 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))   'PreFix: "AB"
Set sortKey2 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))   'Middle ID
Set sortKey3 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))   'PostFix

中间 ID 编号排序(第 2 个辅助列,然后是第 1 个,然后是第 3 个):

Set sortKey1 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))   'Middle ID
Set sortKey2 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))   'PreFix: "AB"
Set sortKey3 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))   'PostFix

要在 PostFix 上排序(第 3 个辅助列,然后是第 2 个,然后是第 3 个):

Set sortKey1 = .Range(.Cells(row1, lCol + 3), .Cells(lRow, lCol + 3))   'PostFix
Set sortKey2 = .Range(.Cells(row1, lCol + 2), .Cells(lRow, lCol + 2))   'Middle ID
Set sortKey3 = .Range(.Cells(row1, lCol + 1), .Cells(lRow, lCol + 1))   'PreFix: "AB"

.

我用你提供的数据进行了测试。以下是结果:

.

.

排序期间 - 说明解析 3 个辅助列中的字符串的结果