2012-10-09 1 views
7

통합 문서에 두 개의 명명 된 범위가 있다고 가정 해 보겠습니다. 두 명명 된 범위는 동일한 이름 ("myName"이라고합시다)을 가지지 만 하나는 Sheet1에 범위가 지정되고 다른 하나는 통합 문서의 범위가됩니다.이름이 중복 될 때 Excel 통합 문서의 문자열로 명명 된 범위 가져 오기

명명 된 범위의 이름 (문자열)이 지정되면 명명 된 범위의 통합 문서 수준을 가져 오려고합니다.

네이티브 호출을 사용하는 경우 : wb.Names.Item("myName"), 범위가 지정된 시트 범위를 반환합니다.

그 대신에 : wb.Names.Item("Sheet1!myName")을 입력하면 시트 범위의 이름 범위가 분명히 반환됩니다. 나는 시트 특정 것들을 지정하기 위해 이것을 사용할 수 있지만 통합 문서는 지정할 수 없다는 것을 알았다.

어쨌든 통합 문서 범위를 지정할 수 있습니까?

해결 방법 현재 모든 해결 방법은 모든 이름 목록을 반복하고 .Name 속성을 비교하여 통합 문서 범위 명명 된 범위를 가져옵니다. .Name 속성을 "Sheet1!"추가하기 때문에이 작동합니다. 시트 범위의 명명 된 범위. 그러나 이것은 매우 비용이 많이 들고, 나는 그것을 피하고 싶습니다.

+2

그것은 나에게 100 % 분명하다 - 합리적으로 빨리 수십 이름의 수천을 제외하고는 우리가 글로벌 이름의 로컬 버전을 찾기 위해 사용하는 최적화 된 VBA 코드는이 범위. 범위 객체를 이름 문자열로 설정하려고하면 Set rng1 = Range ("myName")'은 * sheet1이 활성화 된 경우 로컬 시트 이름에서 범위를 반환합니다 * 그렇지 않으면 통합 문서 이름의 범위를 반환합니다 . 이것은 가장 안전한 해결 방법이라고 생각합니다. 즉, 활성 시트가 ​​통합 문서 범위로 이름을 사용하기 전에 로컬 이름을 호스팅하는 시트와 다른지 테스트합니다. 이해가 되니? :) – brettdj

+0

또한 parent.name을 통합 문서 이름과 비교할 수 있지만 해당 컬렉션을 추출하려면 이름을 반복해야합니다. – nutsch

+0

re : @ brettdj 님의 댓글입니다. 달성하려는 대상에 따라 가장 쉬운 방법은 코드 시작 부분에 임시 시트를 추가하여 코드 끝 부분에서 삭제하는 것입니다. – nutsch

답변

1

우리가 (JKP와 나 자신이) Name Manager을 작성할 때 우리가 특별히 언급 한 Excel 개체 모델 동작이 버그를 찾기 어렵 기 때문에 중복 된 전역/로컬 이름에 대한 필터 및 경고 메시지를 추가했습니다.

내 추천은 절대 중복 된 글로벌/로컬 이름을 사용하지 않아야합니다.

우리는 코드가 로컬 이름의 부모와 전역/로컬이 중복되었는지 감지하고 필요한 경우 시트를 전환합니다. 당신은을 사용하는 방법을

Function FindNameLocal(oSheet As Worksheet, sName As String) As Name 
     Dim oName As Name 
     Dim strLocalName As String 
     Dim strLocalNameNoQuote 
     Dim strName As String 
     Set FindNameLocal = Nothing 
     If Len(sName) > 0 And Not oSheet Is Nothing And oSheet.Names.Count > 0 Then 
      On Error Resume Next 
      strLocalName = "'" & oSheet.Name & "'!" & sName 
      strLocalNameNoQuote = oSheet.Name & "!" & sName 
      Set FindNameLocal = oSheet.Names(strLocalName) 
      If Err <> 0 Or (FindNameLocal.NameLocal <> strLocalName And FindNameLocal.NameLocal <> strLocalNameNoQuote) Then 
       On Error GoTo 0 
       Set FindNameLocal = Nothing 
       For Each oName In oSheet.Names 
        strName = oName.Name 
        If Len(strLocalName) = Len(strName) Or Len(strLocalNameNoQuote) = Len(strName) Then 
         If strName = strLocalName Or strName = strLocalNameNoQuote Then 
          Set FindNameLocal = oName 
          GoTo GoExit 
         End If 
        End If 
       Next 
      End If 
     End If 
GoExit: 
    End Function 
+0

이 질문에 대한 답이 확실하지 않습니다. 어쩌면 나는 그것을 잘못 읽고 있지만, 나는 그 이름의 글로벌 버전을 얻을 필요가있다. 이것은 wb.Names.Item ("Sheet1! myName")의 형식으로 전달하여 이미 수행 할 수있는 시트 레벨 1을 반환합니다. 나는 당신의 코드에서 내가 궁금해하는 한가지를 발견했다. 문자열을 비교하기 전에 길이를 비교해도 성능이 많이 향상됩니까? – Shark

+0

전역 이름과 활성 워크 시트 이름을 전달하여 중복 된 글로벌 - 로컬 이름이 있는지를 탐지하는 데 사용합니다. 중복이있는 경우 워크 시트를 변경하고 중복이 없거나 새 시트를 임시로 추가하는 워크 시트를 찾을 때까지 다시 시도해야합니다. 그러면 이름에 액세스 할 때 전역 이름을 얻을 수 있습니다. VBA에서 문자열의 길이를 얻는 것은 매우 빠르지 만 문자열을 비교하는 속도는 느립니다. C#에서 이것이 어느 정도 적용되는지 모릅니다. –

+0

아, 이제 이해가됩니다. 나는 당신의 접근법 (C#으로 번역 된)이 내가 생각해 낸 또 다른 아이디어보다 빠르지 않으면 안다. 해결책을 다른 답으로 게시 할 것입니다. 그런 다음 성능 테스트가 승자를 결정합니다! – Shark