Find where named ranges are being used in big workbook

后端 未结 3 624
抹茶落季
抹茶落季 2020-12-18 06:22

I have a list of 594 named ranges in a workbook with nearly 20 sheets, each sheet has about 200 columns of data. I need to find out where the named ranges are being used so

3条回答
  •  北荒
    北荒 (楼主)
    2020-12-18 06:46

    Here is one way I can think of. I will explain this in 2 parts.

    PART 1

    Let's say we have a named range Sid.

    This word Sid can appear in any one of these forms as shown in the image below. Why does it start with =? That has been explained in Part2 below.

    =Sid    '<~~ 1
    ="Sid"  '<~~ 2
    =XSid   '<~~ 3
    =SidX   '<~~ 4
    =_Sid   '<~~ 5
    =Sid_   '<~~ 6
    =(Sid)  '<~~ 7
    

    enter image description here

    Any other scenarios, I guess will be a subset of the above. Now out of these the only valid find in our case is the first one and the last one since we are looking for our named range.

    So here is a quick function to check if the cell formula has a named range or not. I am sure it can be made more efficient

    Function isNamedRangePresent(rng As Range, s As String) As Boolean
        Dim sFormula As String
        Dim pos1 As Long, pos2 As Long, sLen As Long, i As Long
    
        sFormula = rng.Formula: sLen = Len(sFormula)
    
        pos2 = 1
    
        Do
            pos1 = InStr(pos2, sFormula, s) - 1
            If pos1 < 1 Then Exit Do
    
            isNamedRangePresent = True
    
            For i = 65 To 90
                '~~> A-Z before Sid for example XSid
                If UCase(Mid(sFormula, pos1, 1)) = Chr(i) Then
                    isNamedRangePresent = False
                    Exit For
                End If
            Next i
    
            '~~> Check for " for example "Sid
            If isNamedRangePresent = True Then _
            If UCase(Mid(sFormula, pos1, 1)) = Chr(34) Then isNamedRangePresent = False
            '~~> Check for underscore for example _Sid
            If isNamedRangePresent = True Then _
            If UCase(Mid(sFormula, pos1, 1)) = Chr(95) Then isNamedRangePresent = False
    
            pos2 = pos1 + Len(s) + 1
    
            If pos2 <= sLen Then
                For i = 65 To 90
                    '~~> A-Z after Sid for example SidX
                    If UCase(Mid(sFormula, pos2, 1)) = Chr(i) Then
                        isNamedRangePresent = False
                        Exit For
                    End If
                Next i
    
                '~~> "Sid
                If isNamedRangePresent = True Then _
                If UCase(Mid(sFormula, pos2, 1)) = Chr(34) Then isNamedRangePresent = False
                '~~> _Sid
                If isNamedRangePresent = True Then _
                If UCase(Mid(sFormula, pos2, 1)) = Chr(95) Then isNamedRangePresent = False
            End If
        Loop
    End Function
    

    So in the first and the last case, Debug.Print isNamedRangePresent(Range("D2"), "Sid") will give you True See this

    enter image description here

    PART 2

    Now coming to the .Find. I see that you are searching only once in the worksheet. Since you can have many scenarios of the word Sid being present, you cannot just have one .Find. You will have to use .FindNext. See THIS link on how to use that. I have explained it there so I won't bother explaining that here.

    We can make our .Find more efficient by searching only those cells which has formulas. To do that we have to use .SpecialCells(xlCellTypeFormulas). This explains why we had "=" in our example in PART1. :)

    Here is an example (PART1 Code added at the bottom)

    Sub Sample()
        Dim oRange As Range, aCell As Range, bCell As Range
        Dim oSht As Worksheet
        Dim strSearch As String, FoundAt As String
    
        Set oSht = Worksheets("Sheet1")
    
        '~~> Set your range where you need to find - Only Formula Cells
        On Error Resume Next
        Set oRange = oSht.Cells.SpecialCells(xlCellTypeFormulas)
        On Error GoTo 0
    
        If Not oRange Is Nothing Then
            strSearch = "Sid"
    
            Set aCell = oRange.Find(What:=strSearch, LookIn:=xlFormulas, _
                        LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                        MatchCase:=False, SearchFormat:=False)
    
            If Not aCell Is Nothing Then
                Set bCell = aCell
    
                '~~> Check if the cell has named range
                If isNamedRangePresent(aCell, strSearch) Then FoundAt = aCell.Address
    
                Do
                    Set aCell = oRange.FindNext(After:=aCell)
    
                    If Not aCell Is Nothing Then
                        If aCell.Address = bCell.Address Then Exit Do
    
                        '~~> Check if the cell has named range
                        If isNamedRangePresent(aCell, strSearch) Then FoundAt = FoundAt & ", " & aCell.Address
                    Else
                        Exit Do
                    End If
                Loop
            Else
                MsgBox SearchString & " not Found"
                Exit Sub
            End If
    
            If FoundAt = "" Then
                MsgBox "The Named Range was not found"
            Else
                MsgBox "The Named Range has been found these locations: " & FoundAt
            End If
        End If
    End Sub
    
    Function isNamedRangePresent(rng As Range, s As String) As Boolean
        Dim sFormula As String
        Dim pos1 As Long, pos2 As Long, sLen As Long, i As Long
    
        sFormula = rng.Formula: sLen = Len(sFormula)
    
        pos2 = 1
    
        Do
            pos1 = InStr(pos2, sFormula, s) - 1
            If pos1 < 1 Then Exit Do
    
            isNamedRangePresent = True
    
            For i = 65 To 90
                '~~> A-Z before Sid for example XSid
                If UCase(Mid(sFormula, pos1, 1)) = Chr(i) Then
                    isNamedRangePresent = False
                    Exit For
                End If
            Next i
    
            '~~> Check for " for example "Sid
            If isNamedRangePresent = True Then _
            If UCase(Mid(sFormula, pos1, 1)) = Chr(34) Then isNamedRangePresent = False
            '~~> Check for underscore for example _Sid
            If isNamedRangePresent = True Then _
            If UCase(Mid(sFormula, pos1, 1)) = Chr(95) Then isNamedRangePresent = False
    
            pos2 = pos1 + Len(s) + 1
    
            If pos2 <= sLen Then
                For i = 65 To 90
                    '~~> A-Z after Sid for example SidX
                    If UCase(Mid(sFormula, pos2, 1)) = Chr(i) Then
                        isNamedRangePresent = False
                        Exit For
                    End If
                Next i
    
                '~~> "Sid
                If isNamedRangePresent = True Then _
                If UCase(Mid(sFormula, pos2, 1)) = Chr(34) Then isNamedRangePresent = False
                '~~> _Sid
                If isNamedRangePresent = True Then _
                If UCase(Mid(sFormula, pos2, 1)) = Chr(95) Then isNamedRangePresent = False
            End If
        Loop
    End Function
    

    Output

    enter image description here

    PHEW!!!

提交回复
热议问题