Как изменить область с именованным диапазоном
Когда я создаю именованный диапазон через диспетчер имен, мне предоставляется возможность указать рабочую книгу или область [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 установлено значение "Рабочая книга" и нажмите "Закрыть".