Как изменить область с именованным диапазоном

Когда я создаю именованный диапазон через диспетчер имен, мне предоставляется возможность указать рабочую книгу или область [worksheet name]. Но если вы хотите изменить область видимости, выпадающее меню будет недоступно. Есть ли способ в диспетчере имен или, желательно, VBA, чтобы изменить область существующего именованного диапазона?

Например:

  • testName относится к 'sheet1'!A1:B2 с объемом рабочей книги. Как я могу изменить это на
  • testName относится к 'sheet1'!A1:B2 с областью 'sheet1'?

Ответы

Ответ 1

Вы можете скачать бесплатную добавку Name Manager, разработанную мной и Jan Karel Pieterse, из http://www.decisionmodels.com/downloads.htm Это позволяет выполнять многие операции с именами, которые менеджер имен Excel 2007 не может обрабатывать, включая изменение объема имен.

В VBA:

Sub TestName()
Application.Calculation = xlManual
Names("TestName").Delete
Range("Sheet1!$A$1:$B$2").Name = "Sheet1!TestName"
Application.Calculation = xlAutomatic
End Sub

Ответ 2

Проверьте эти две подпрограммы, которые обращают друг друга и переворачивают область (рабочий лист в рабочую книгу или наоборот) всех именованных диапазонов, которые относятся к диапазону на активном листе.

 Option Explicit
'---------------------------------------------------------------------------------------
' Procedure : RescopeNamedRangesToWorkbook
' Author    : JS20'07'11
' Date      : 11/18/2013
' Purpose   : Rescopes the parent of worksheet scoped named ranges to the active workbook
' for each named range with a scope equal to the active sheet in the active workbook.
'---------------------------------------------------------------------------------------

Public Sub RescopeNamedRangesToWorkbook()
Dim wb As Workbook
Dim ws As Worksheet
Dim objName As Name
Dim sWsName As String
Dim sWbName As String
Dim sRefersTo As String
Dim sObjName As String
Set wb = ActiveWorkbook
Set ws = ActiveSheet
sWsName = ws.Name
sWbName = wb.Name

'Loop through names in worksheet.
For Each objName In ws.Names
'Check name is visble.
    If objName.Visible = True Then
'Check name refers to a range on the active sheet.
        If InStr(1, objName.RefersTo, sWsName, vbTextCompare) Then
            sRefersTo = objName.RefersTo
            sObjName = objName.Name
'Check name is scoped to the worksheet.
            If objName.Parent.Name <> sWbName Then
'Delete the current name scoped to worksheet replacing with workbook scoped name.
                sObjName = Mid(sObjName, InStr(1, sObjName, "!") + 1, Len(sObjName))
                objName.Delete
                wb.Names.Add Name:=sObjName, RefersTo:=sRefersTo
            End If
        End If
    End If
Next objName
End Sub
'---------------------------------------------------------------------------------------
' Procedure : RescopeNamedRangesToWorksheet
' Author    : JS20'07'11
' Date      : 11/18/2013
' Purpose   : Rescopes each workbook scoped named range to the specific worksheet to
' which the range refers for each named range that refers to the active worksheet.
'---------------------------------------------------------------------------------------

Public Sub RescopeNamedRangesToWorksheet()
Dim wb As Workbook
Dim ws As Worksheet
Dim objName As Name
Dim sWsName As String
Dim sWbName As String
Dim sRefersTo As String
Dim sObjName As String
Set wb = ActiveWorkbook
Set ws = ActiveSheet
sWsName = ws.Name
sWbName = wb.Name

'Loop through names in worksheet.
For Each objName In wb.Names
'Check name is visble.
    If objName.Visible = True Then
'Check name refers to a range on the active sheet.
        If InStr(1, objName.RefersTo, sWsName, vbTextCompare) Then
            sRefersTo = objName.RefersTo
            sObjName = objName.Name
'Check name is scoped to the workbook.
            If objName.Parent.Name = sWbName Then
'Delete the current name scoped to workbook replacing with worksheet scoped name.
                objName.Delete
                ws.Names.Add Name:=sObjName, RefersTo:=sRefersTo
            End If
        End If
    End If
Next objName
End Sub

Ответ 3

Я нашел решение! Просто скопируйте лист с вашими именованными переменными. Затем удалите исходный лист. Скопированный лист теперь будет иметь одинаковые именованные переменные, но с локальной областью (scope = скопированный лист).

Однако я не знаю, как перейти от локальных переменных к глобальным.

Ответ 4

здесь, как я продвигаю все имена рабочих листов на глобальные имена. YMMV

For Each wsh In ActiveWorkbook.Worksheets
For Each n In wsh.Names
    ' Get unqualified range name
    Dim s As String
    s = Split(n.Name, "!")(UBound(Split(n.Name, "!")))
    ' Add to "Workbook" scope
    n.RefersToRange.Name = s
    ' Remove from "Worksheet" scope
    Call n.Delete
Next n
Next wsh

Ответ 5

создайте новое имя с нуля и удалите старый.

Ответ 6

Альтернативный способ - "взломать" файл Excel на 2007 или выше, хотя рекомендуется позаботиться о том, чтобы сделать это, и сохранить резервную копию оригинала:

Сначала сохраните таблицу Excel как файл .xlsx или .xlsm(а не двоичный). переименуйте файл в .zip, затем распакуйте. Перейдите в папку xl в структуре zip и откройте workbook.xml в Wordpad или аналогичный текстовый редактор. Именованные диапазоны находятся в тегах definedName. Локальное определение области определяется localSheetId = "x" (идентификаторы листов можно найти, нажав Alt-F11 в Excel, с открытой таблицей, чтобы перейти в окно VBA, а затем посмотрев на панель "Проект" ). Скрытые диапазоны определяются hidden = "1", поэтому просто удалите скрытый = "1", чтобы отобразить, например.

Теперь измените структуру папок, соблюдая целостность структуры папок и переименуйте обратно в .xlsx или .xlsm.

Это, вероятно, не лучшее решение, если вам нужно изменить область или скрыть/отобразить большое количество определенных диапазонов, хотя она отлично подходит для создания одной или двух небольших настроек.

Ответ 7

Это все еще нуждается в дополнительной очистке, однако работает со всеми простыми ссылками, не убивая существующие локальные имена.

Type GlobalNamesToLocalNames_Type
   Name As String
   Sheet As String
   Ref As String
End Type

Sub GlobalNamesToLocalNames(Optional Void As Variant)
   Dim List() As GlobalNamesToLocalNames_Type
   Dim Count As Long
   Dim Name As Name
   Dim Dat() As String
   Dim X As Long

   ' count the size
   For Each Name In ActiveWorkbook.Names
      Count = Count + 1
   Next
   ReDim List(Count - 1)
   Count = 0

   ' Collecect all name data
   For Each Name In ActiveWorkbook.Names
      With List(Count)
         ' Pick up only the name
         If InStr(Name.Name, "!") > 0 Then
            Dat = Split(Name.Name, "!")
            .Name = Dat(1)
         Else
            .Name = Name.Name
         End If
         ' pick up the sheet and refer
         Dat = Split(Name.RefersTo, "!")
         .Sheet = Mid(Dat(0), 2)
         .Ref = Dat(1)
         ' make local sheet name
         .Name = .Sheet & "!" & .Name
      End With
      Count = Count + 1
   Next

   ' Delete all names
   For Each Name In ActiveWorkbook.Names
      Name.Delete
   Next

   'rebuild all the names
   For X = 0 To Count - 1
      With List(X)
         If Left(.Ref, 1) <> "#" Then
            ActiveWorkbook.Names.Add Name:=.Name, RefersToLocal:="=" & .Sheet & "!" & .Ref
         End If
      End With
   Next
End Sub

Ответ 8

Для меня это работает, когда я создаю новый тег имени для того же диапазона из Диспетчер имен, он дает мне возможность изменять область;) рабочая книга по умолчанию и может быть изменен на любой из доступных листов.

Ответ 9

Код JS20'07'11 действительно невероятный, простой и прямой. Одно из предложений, которое я хотел бы дать, - поставить восклицательный знак в условиях:

InStr(1, objName.RefersTo, sWsName+"!", vbTextCompare)

Потому что это предотвратит добавление NamedRange в неправильный Лист. Например: Если NamedRange ссылается на Лист с именем Plan11, и у вас есть другой лист с именем Plan1, код может немного испортить, добавив диапазоны, если вы не используете восклицательный знак.

UPDATE

Коррекция: Лучше всего использовать регулярное выражение для оценки имени Листа. Простая функция, которую вы можете использовать, следующая (адаптировано http://blog.malcolmp.com/2010/regular-expressions-excel-add-in, включить Microsoft VBScript Regular Expressions 5.5):

Function xMatch(pattern As String, searchText As String, Optional matchIndex As Integer = 1, Optional ignoreCase As Boolean = True) As String
On Error Resume Next
Dim RegEx As New RegExp
RegEx.Global = True
RegEx.MultiLine = True
RegEx.pattern = pattern
RegEx.ignoreCase = ignoreCase
Dim matches As MatchCollection
Set matches = RegEx.Execute(searchText)
Dim i As Integer
i = 1
For Each Match In matches
    If i = matchIndex Then
        xMatch = Match.Value
    End If
    i = i + 1
Next
End Function

Итак, вы можете использовать что-то вроде этого:

xMatch("'?" +sWsName + "'?" + "!", objName.RefersTo, 1) <> ""

вместо

InStr(1, objName.RefersTo, sWsName+"!", vbTextCompare)

Это будет охватывать варианты Plan1 и 'Plan1' (когда диапазон относится к более чем одной ячейке)

СОВЕТ. Избегайте имен листов с одинарными кавычками ('),:).

Ответ 10

Эти ответы были полезны при решении подобной проблемы при попытке определить именованный диапазон с областью Workbook. "Ah-HA!" для меня нужно использовать коллекцию имен, относящуюся ко всей книге! Это может повторить очевидное для многих, но в моих исследованиях это не было четко указано, поэтому я разделяю для других аналогичные вопросы.

' Local / Worksheet only scope
Worksheets("Sheet2").Names.Add Name:="a_test_rng1", RefersTo:=Range("A1:A4")

' Global / Workbook scope
ThisWorkbook.Names.Add Name:="a_test_rng2", RefersTo:=Range("B1:b4") 

Если вы посмотрите на свой список имен, когда Sheet2 активен, оба диапазона есть, но переключаются на любой другой лист, а "a_test_rng1" нет.

Теперь я могу с радостью создать именованный диапазон в моем коде, с тем, что я считаю подходящим. Не нужно путаться с менеджером имен или подключением.


Кроме того, менеджер названий в Excel Mac 2011 беспорядок, но я обнаружил, что, хотя нет меток столбцов, чтобы рассказать вам, что вы смотрите при просмотре списка названных диапазонов, если есть лист, указанный рядом с именем это имя ограничено листом/локальным. Смотрите прилагаемый скриншот.

Excel Mac 2011 Name Manager

Полный кредит в этой статье для сборки частей.

Ответ 11

Я добавил несколько дополнительных строк кода в JS20'07'11 предыдущего Makro, чтобы убедиться, что имя листа Named Ranges уже не является именем рабочей книги Named Ranges. Без этих строк уже определенный заданный диапазон именованных книг удаляется и заменяется.

Public Sub RescopeNamedRangesToWorkbookV2()
Dim wb As Workbook
Dim ws As Worksheet
Dim objNameWs As Name
Dim objNameWb As Name
Dim sWsName As String
Dim sWbName As String
Dim sRefersTo As String
Dim sObjName As String
Set wb = ActiveWorkbook
Set ws = ActiveSheet
sWsName = ws.Name
sWbName = wb.Name

'Loop through names in worksheet.
For Each objNameWs In ws.Names


'Check name is visble.
    If objNameWs.Visible = True Then
'Check name refers to a range on the active sheet.
        If InStr(1, objNameWs.RefersTo, sWsName, vbTextCompare) Then
            sRefersTo = objNameWs.RefersTo
            sObjName = objNameWs.Name
'Check name is scoped to the worksheet.
            If objNameWs.Parent.Name <> sWbName Then
'Delete the current name scoped to worksheet replacing with workbook scoped name.
                sObjName = Mid(sObjName, InStr(1, sObjName, "!") + 1, Len(sObjName))
'Check to see if there already is a Named Range with the same Name with the full workbook scope.
                For Each objNameWb In wb.Names
                    If sObjName = objNameWb.Name Then
                    MsgBox "There is already a Named range with ""Workbook scope"" named """ + sObjName + """. Change either Named Range names or delete one before running this Macro."
                    Exit Sub
                    End If
                Next objNameWb
                objNameWs.Delete
                wb.Names.Add Name:=sObjName, RefersTo:=sRefersTo
            End If
        End If
    End If
Next objNameWs
End Sub

Ответ 12

Нашел это на theexceladdict.com

  • Выберите нужный диапазон на вашем листе, объем которого вы хотите изменить,

  • Откройте Диспетчер имен (вкладка "Формулы" ) и выберите имя;

  • Нажмите "Удалить" и "ОК";

  • Нажмите "Создать..." и введите исходное имя в поле "Имя";

  • Убедитесь, что в области Scope установлено значение "Рабочая книга" и нажмите "Закрыть".