根据在主工作表中特定列的字符串中找到的关键字,将行从一个工作表移动到特定工作表

Moving rows from one worksheet to specific worksheets based on keywords found in string in a specific column in master worksheet

我有一个名为“Main”的 Excel 作品sheet,其中包含一定数量的列,其中一列包含与需要安装的补丁有关的不同代码 (CVE) 的列表根据互联网上的标准在工作sheets。

要搜索的代码不是固定格式,而是包含代码的字符串。

我根据这些字符串中的关键字手动创建了一些作品sheet,最终将包含主sheet的所有行,但仅包含由名称定义的行我要的关键字。

例如,我有一个名为“Microsoft”的作品sheet,它应该包含主 sheet 中引用 Microsoft CVE 的所有行,基于对字符串的搜索和发现“微软”这个词。 Adobe 等也一样。

我创建了一个脚本来复制行,并创建了一个新索引 sheet,列出了为每个关键字找到的行数,这些关键字已从主 sheet 复制到相关 sheet.

这就是我迷路的地方。

我有18个作品sheet也是关键词。我可以定义一个关键字,然后从主要作品sheet 中复制所有内容作为一个关键字。

我需要一个循环(可能是循环中的循环)来读取索引中定义的作品sheet 名称,搜索所有包含关于该关键字的 CVE 的相关行,然后复制将我创建的相关作品sheet 的行移至该作品的相关行sheet.
例如,如果我复制了两行,下一个应该写到下一行,依此类推,直到我遍历了所有 worksheet (关键字)名称并到达最后一个之后的空行索引中的名称 sheet.

我的代码,只设置了一个关键字用于有限的 运行 测试工作。
我需要遍历所有关键字并复制所有数据。
最后想把master worksheet(Main)的相关行复制到relevant worksheet(根据Index worksheet中的关键词worksheet名称=]), 并删除复制母版后的行sheet.
我最终应该将所有数据分成相关工作 sheet 和一个空的(headers 除外)主工作 sheet.

这是我目前所拥有的(来自各种示例和我自己的东西)。

Public WSNames() As String
Public WSNum() As Long
Public I As Long
Public ShtCount As Long

Sub MoveBasedOnValue()

    Dim CVETitle As String
    
    Dim xRg As Range
    Dim xCell As Range

    Dim A As Long
    Dim B As Long
    Dim C As Long
    Dim D As Long
    Dim CountCop As Long
   
    A = Worksheets("Main").UsedRange.Rows.Count
    A = A + 1
    
    'Create an index of the worksheet names to work with for moving the data and counting the lines in the WS
    ReadWSNames
    
    B = Worksheets(WSNames(2)).UsedRange.Rows.Count
    B = B + 1 'Place under the last row for start

    'Range to read and scan from
    Set xRg = Worksheets("Main").Range("E5:E" & A)

    On Error Resume Next
    Application.ScreenUpdating = False
    
    'For C = 1 To xRg.Count
    For C = 1 To 5
    
       'Read in the string to search from the Main WS
        CVETitle = CStr(xRg(C).Value)
    
       'Find if the word we want exists in the string
        If InStr(1, CVETitle, WSNames(2)) > 0 Then
            xRg(C).EntireRow.Copy Destination:=Worksheets(WSNames(2)).Range("A" & B + 1)
            CountCop = Worksheets("Index").Range("B3").Value
            CountCop = CountCop + 1
            Worksheets("Index").Range("B3").Value = CountCop
            'xRg(C).EntireRow.Delete
            'If CStr(xRg(C).Value) = WSNames(2) Then
            'C = C - 1
        'End If

            B = B + 1

        End If

    Next

    Application.ScreenUpdating = True

End Sub


Sub ReadWSNames()

    ReDim WSNames(1 To ActiveWorkbook.Sheets.Count)
    ReDim WSNum(1 To ActiveWorkbook.Sheets.Count)
    
    Dim MyIndex As Worksheet
    
    ShtCount = Sheets.Count

   'Read sheetnames and number of lines in each WS into arrays and clear the sheets other than the main one
    If Not IndexExists("Index") Then
        For I = 1 To ShtCount
            WSNames(I) = Sheets(I).Name
            If WSNames(I) <> "Main" Then ActiveWorkbook.Worksheets(WSNames(I)).Range("5:10000").EntireRow.Delete
            WSNum(I) = Worksheets(WSNames(I)).UsedRange.Rows.Count
            WSNum(I) = WSNum(I) - 3
        Next I
        'Add an index worksheet before the main worksheet and make sure one doesn't exist
        Worksheets.Add Before:=Worksheets(1)
        ActiveSheet.Name = "Index" 'Give new Ws a name
        Application.DefaultSheetDirection = xlLTR 'Make direction suited to English
        'Write headers and set parameters
        Range("A1").Value = "WS Names"
        Range("B1").Value = "Count"
        With Range("A1:B1")
            .Font.Size = 14
            .Font.Bold = True
            .Font.Color = vbBlue
        End With
        Columns("A:B").AutoFit
        Columns("B:B").HorizontalAlignment = xlCenter
        'Write data from arrays into Index WS
        ActiveCell.Offset(1, 0).Select
        For I = 1 To ShtCount 'Write values to Index WS
            ActiveCell.Value = WSNames(I) 'Write Worksheet name
            ActiveCell.Offset(0, 1) = WSNum(I) 'Write number of rows already existing in Ws
            ActiveCell.Offset(1, 0).Select 'Move one cell down
        Next I
        Worksheets("Index").Activate 'Make Index the active ws
        Range("A2").Select 'Select first cell to read data from
        I = 1
        X = 2
        Do While Not IsEmpty(Range("A" & X)) 'Read values back into array to make sure i's all there
            WSNames(I) = ActiveCell.Value
            WSNum(I) = ActiveCell.Offset(0, 1).Value
            ActiveCell.Offset(1, 0).Select 'Move one cell down
            I = I + 1
            X = X + 1
        Loop
        Worksheets("Main").Activate 'Make Main the active ws
    Else 'If Index exists, simply read the data into the arrays
        Worksheets("Index").Activate 'Make Index the active ws
        Range("A2").Select 'Select first cell to read data from
        I = 1
        X = 2
        Do While Not IsEmpty(Range("A" & X)) 'Read values back into array to make sure i's all there
            WSNames(I) = ActiveCell.Value
            WSNum(I) = ActiveCell.Offset(0, 1).Value
            ActiveCell.Offset(1, 0).Select 'Move one cell down
            I = I + 1
            X = X + 1
        Loop
        Worksheets("Main").Activate 'Make Main the active ws
    Exit Sub
    End If
    
End Sub


Function IndexExists(sSheet As String) As Boolean
On Error Resume Next
    sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function

因为CVE字符串不一样,没法排序,所以可以一行一个微软的CVE,然后几行其他的CVE,再微软的,以此类推。

我试图post索引作品sheet、作品sheet名称和行中数据示例的图片示例,但我没有足够的声望。

因此,搜索关键字(E 列)的字符串数据的几个示例(超过 7,000 行):

*[MS20-DEC] Microsoft Windows Cloud Files Mini Filter Driver Elevation of Privilege Vulnerability - CVE-2020-17134 [APSB16-04]


*Adobe Flash Player <20.0.0.306 Remote Code Execution Vulnerability - CVE-2016-0964 [MS21-JUN] * 

*Microsoft Kerberos AppContainer Security Feature Bypass Vulnerability - CVE-2021-31962


*McAfee Agent <5.6.6 Local Privilege Escalation Vulnerability - CVE-2020-7311


*7-Zip <18.00 and p7zip Multiple Memory Corruption Vulnerabilities - CVE-2018-5996

在 sheet 中扫描一个词,然后在 sheet Main 中向下扫描该词的字符串。向上扫描 sheet 以删除行。

更新 - 每个 sheet

多个单词
Option Explicit
Sub SearchWords()

    Const COL_TEXT = "E"
    Const ROW_TEXT = 5 ' first line of text

    Dim wb As Workbook
    Dim ws As Worksheet, wsMain As Worksheet, wsIndex As Worksheet
    Dim arData(), arDelete() As Boolean
    Dim lastrow As Long, i As Long, n As Long, r As Long
    Dim word As String, txt As String
    Dim t0 As Single: t0 = Timer
    Dim w
    
    ' create index if not exists
    CreateIndex
    
    Set wb = ActiveWorkbook
    With wb
        Set wsMain = .Sheets("Main")
        Set wsIndex = .Sheets("Index")
    End With
    
    ' copy strings into array for speed
    With wsMain
         lastrow = .Cells(.Rows.Count, COL_TEXT).End(xlUp).Row
         If lastrow < ROW_TEXT Then
             MsgBox "No text found in column " & COL_TEXT, vbCritical
             Exit Sub
         End If
         arData = .Cells(1, COL_TEXT).Resize(lastrow).Value2
         ReDim arDelete(1 To lastrow)
    End With
    
    ' scan main for each keyword in index
    i = 2 ' index row
    Application.ScreenUpdating = False
    For Each ws In wb.Sheets
        If ws.Name <> "Index" And ws.Name <> "Main" Then
            'word = ws.Name
            lastrow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Row
            For Each w In Split(ws.Name, "+")
                word = Trim(w)
                For r = ROW_TEXT To UBound(arData)
                    txt = arData(r, 1)
                    If InStr(1, txt, word, vbTextCompare) > 0 Then
                        lastrow = lastrow + 1
                        wsMain.Rows(r).Copy ws.Cells(lastrow, 1)
                        arDelete(r) = True
                        n = n + 1
                    End If
                Next
            Next
        
            ' update index
            wsIndex.Cells(i, 1) = ws.Name
            wsIndex.Cells(i, 2) = lastrow - 1
            i = i + 1
        End If
    Next
    
    ' delete or highlight rows
    ' scan upwards
    For r = UBound(arDelete) To ROW_TEXT Step -1
       If arDelete(r) = True Then
           wsMain.Cells(r, COL_TEXT).Interior.Color = vbYellow
           'wsMain.Rows(r).Delete 'uncomment to delete
       End If
    Next
    Application.ScreenUpdating = True
    
    MsgBox n & " lines copied", vbInformation, Format(Timer - t0, "0.0 secs")

End Sub

Sub CreateIndex()

    Dim ws As Worksheet, bHasIndex As Boolean
    For Each ws In Sheets
        If ws.Name = "Index" Then bHasIndex = True
    Next
    
    ' create index
    If Not bHasIndex Then
        Worksheets.Add(before:=Sheets(1)).Name = "Index"
    End If
    
    ' format index
    With Sheets("Index")
        .Cells.Clear
        With .Range("A1:B1")
            .Value2 = Array("WS Names", "Count")
            .Font.Size = 14
            .Font.Bold = True
            .Font.Color = vbBlue
        End With
        .Columns("A:B").AutoFit
        .Columns("B:B").HorizontalAlignment = xlCenter
    End With

End Sub