Проверьте или проверьте, существует ли лист

115
Dim wkbkdestination As Workbook
Dim destsheet As Worksheet

For Each ThisWorkSheet In wkbkorigin.Worksheets 
    'this throws subscript out of range if there is not a sheet in the destination 
    'workbook that has the same name as the current sheet in the origin workbook.
    Set destsheet = wkbkdestination.Worksheets(ThisWorkSheet.Name) 
Next

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

Как я могу проверить, существует ли этот лист? Что-то вроде:

If wkbkdestination.Worksheets(ThisWorkSheet.Name) Then 
YSE
источник
2
возможный дубликат Excel VBA, если рабочий лист ("wsName") существует
sancho.s ReinstateMonicaCellio

Ответы:

173

Некоторым не нравится этот подход из-за «неуместного» использования обработки ошибок, но я думаю, что он считается приемлемым в VBA ... Альтернативный подход - зацикливать все листы, пока не найдете совпадение.

Function WorksheetExists(shtName As String, Optional wb As Workbook) As Boolean
    Dim sht As Worksheet

    If wb Is Nothing Then Set wb = ThisWorkbook
    On Error Resume Next
    Set sht = wb.Sheets(shtName)
    On Error GoTo 0
    WorksheetExists = Not sht Is Nothing
End Function
Тим Уильямс
источник
5
Полностью одобряю использование IMO. Это ловушка для того, что постулируется как существующее, но не существует и имеет долгую историю - cf perl strict, STAE и т. Д. Проголосовали за
Wudang
13
Вероятно, следует использовать ActiveWorkbookвместо ThisWorkbook. Последнее относится к книге, содержащей код макроса, который может отличаться от книги, которую нужно тестировать. Думаю, это ActiveWorkbookбыло бы полезно в большинстве случаев (хотя надуманные ситуации всегда доступны).
sancho.s ReinstateMonicaCellio
3
sht Is Nothingбудет , Trueесли нет листа с этим именем, но мы хотим , чтобы вернуться , Trueесли есть лист с таким именем, следовательно, нет. Это немного проще (но не действует) , если переставить немного кSheetExists = sht Is Not Nothing
Тим Уильямс
3
Приятно отметить, что если вы запустите этот код в своей личной книге макросов, измените его с If wb Is Nothing Then Set wb = ThisWorkbookнаIf wb Is Nothing Then Set wb = ActiveWorkbook
Хенрик К.
2
Это очень эффективный подход (см. Мои комментарии о контрольных точках под ответом Рори ниже), так что кого волнует, что думают недоброжелатели. Обратите внимание (на данный момент) у вас ноль голосов против.
rory.ap
107

Если вас особенно интересуют только рабочие листы, вы можете использовать простой вызов Evaluate:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function
Рори
источник
14
@Rory Я провел несколько тестов по этому вопросу против ответа Тима Вильямса. Более 500000 циклов, у вас - 22 секунды, у Тима - <1.
rory.ap
17
@roryap - если вам нужно запустить это 500000 раз, вам нужно полностью переосмыслить свой подход. ;)
Rory
9
@roryap - однако при использовании нескольких медленных методов начнется накопление секунд. Я бы сказал, что это чрезвычайно ценная информация, так как «приложения» Excel начинают довольно легко
набирать
4
@roryap - в чем ценность этой информации для разговора? Я просто утверждаю, что рассредоточение неэффективных методов по вашему коду замедлит работу приложения в целом. Вы тестируете это 500 тысяч раз - это здорово, и я благодарю вас за это, 22 секунды - это не очень хорошо. (Я согласен с вами)
tedcurrent
6
Даже если он медленнее, он выглядит намного более чистым решением, чем принятый ответ. +1 от меня.
Саша Л.
49

Для этого вам не нужна обработка ошибок. Все, что вам нужно сделать, это перебрать все рабочие листы и проверить, существует ли указанное имя:

For i = 1 To Worksheets.Count
    If Worksheets(i).Name = "MySheet" Then
        exists = True
    End If
Next i

If Not exists Then
    Worksheets.Add.Name = "MySheet"
End If
фбонетти
источник
21

Поскольку проверка членов коллекции - это общая проблема, вот абстрактная версия ответа Тима:

Функция содержит (objCollection как объект, strName как String) как логическое
    Dim o as Object
    При ошибке Возобновить Далее
    установить o = objCollection (strName)
    Содержит = (Err.Number = 0)
    Err.Clear
 Конечная функция

Эта функция может быть использована с любой коллекцией как объект ( Shapes, Range, Names, Workbooksи т.д.).

Чтобы проверить наличие листа, используйте If Contains(Sheets, "SheetName") ...

Питер Альберт
источник
5
Это не отлавливает примитивные типы в коллекциях, так как Setключевое слово вызывает ошибку . Я обнаружил, что вместо того, чтобы использовать Set, запрос TypeNameчлена коллекции работает для всех случаев, то естьTypeName objCollection(strName)
civilkong
2
@Peter: Лучше всего добавить что-нибудь, чтобы очистить ошибку, которая будет возникать в случае отсутствия до завершения функции - либо err.clear, либо On Error Resume Next. В противном случае обработка ошибок в вызывающей процедуре может быть непреднамеренно запущена в следующих случаях. Sub Test() On Error GoTo errhandler Debug.Print Contains(Workbooks, "SomeBookThatIsNotOpen") errhandler: If Err.Number <> 0 Then Stop End Sub
Джеффрейвейр
16

Исправлено: Без обработки ошибок:

Function CheckIfSheetExists(SheetName As String) As Boolean
      CheckIfSheetExists = False
      For Each WS In Worksheets
        If SheetName = WS.name Then
          CheckIfSheetExists = True
          Exit Function
        End If
      Next WS
End Function
Шай Алон
источник
14

В случае , если кто -то хочет , чтобы избежать VBA и тест , если таблица существует чисто в формуле ячейки, можно с помощью ISREFи INDIRECTфункции:

=ISREF(INDIRECT("SheetName!A1"))

Это вернется, TRUEесли книга содержит лист с именем SheetNameи в FALSEпротивном случае.

Виртуальный Майкл
источник
12

Я написал это:

Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function
AOBR
источник
1
Отличная функция! Он не только быстрый, но и самый лаконичный.
ChrisB
Я полагаю, что это ответ, который больше всего соответствует вопросу
Хуан Джойя
Мне нравится этот. Обратите внимание, что он основан на том факте, что значение по умолчанию для sheetExist будет False, поскольку это логическая функция. Оператор присваивания фактически не присваивает значение False для sheetExist, если лист не существует, он просто выдает ошибку и оставляет значение по умолчанию на месте. Если вы хотите, вы можете полагаться на тот факт, что любое ненулевое значение, присвоенное логической переменной, даст результат True и исключит сравнение> 0, например: sheetExist = ActiveWorkbook.Sheets(sSheet).Index
oddacorn
5

Мое решение очень похоже на Tims, но также работает в случае листов, отличных от рабочих листов - диаграмм

Public Function SheetExists(strSheetName As String, Optional wbWorkbook As Workbook) As Boolean
    If wbWorkbook Is Nothing Then Set wbWorkbook = ActiveWorkbook 'or ThisWorkbook - whichever appropriate
    Dim obj As Object
    On Error GoTo HandleError
    Set obj = wbWorkbook.Sheets(strSheetName)
    SheetExists = True
    Exit Function
HandleError:
    SheetExists = False
End Function

.

уилдрикс
источник
3

Поместите тест в функцию, и вы сможете повторно использовать его, и у вас будет лучшая читаемость кода.

НЕ используйте команду «Возобновить после ошибки», поскольку она может конфликтовать с другой частью вашего кода.

Sub DoesTheSheetExists()
    If SheetExist("SheetName") Then
        Debug.Print "The Sheet Exists"
    Else
        Debug.Print "The Sheet Does NOT Exists"
    End If
End Sub

Function SheetExist(strSheetName As String) As Boolean
    Dim i As Integer

    For i = 1 To Worksheets.Count
        If Worksheets(i).Name = strSheetName Then
            SheetExist = True
            Exit Function
        End If
    Next i
End Function
Мартин Карлссон
источник
3

Спустя много лет, но мне просто нужно было это сделать, и мне не понравилось ни одно из опубликованных решений ... Так что я придумал одно, и все благодаря магии (жест радужной руки Губки Боба) "Evaluate ()"!

Evaluate("IsError(" & vSheetName & "!1:1)")

Возвращает ИСТИНА, если Лист НЕ существует; ЛОЖЬ, если лист ДЕЙСТВИТЕЛЬНО существует. Вы можете заменить любой диапазон на «1: 1», но я не советую использовать одну ячейку, потому что, если она содержит ошибку (например, # N / A), она вернет True.

X37V
источник
3

Компактная wsExistsфункция ( без обработки ошибок!)

Вот короткая и простая функция, которая не полагается на обработку ошибок, чтобы определить, существует ли рабочий лист ( и правильно объявлено, что оно работает в любой ситуации!)

Function wsExists(wsName As String) As Boolean
    Dim ws: For Each ws In Sheets
    wsExists = (wsName = ws.Name): If wsExists Then Exit Function
    Next ws
End Function

Пример использования:

В следующем примере добавляется новый рабочий лист с именем myNewSheet, если он еще не существует:

If Not wsExists("myNewSheet") Then Sheets.Add.Name = "myNewSheet"

Больше информации:

ashleedawg
источник
2

Почему бы просто не использовать небольшой цикл, чтобы определить, существует ли указанный лист? Скажем, если вы искали Рабочий лист с именем «Лист1» в текущей открытой книге.

Dim wb as Workbook
Dim ws as Worksheet

Set wb = ActiveWorkbook

For Each ws in wb.Worksheets

    if ws.Name = "Sheet1" then
        'Do something here
    End if

Next
ScottMcC
источник
2

Если вы поклонник WorksheetFunction.или работаете из неанглоязычной страны с неанглоязычным Excel, это хорошее решение, которое работает:

WorksheetFunction.IsErr(Evaluate("'" & wsName & "'!A1"))

Или в такой функции:

Function WorksheetExists(sName As String) As Boolean
    WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
Vityata
источник
1
Public Function WorkSheetExists(ByVal strName As String) As Boolean
   On Error Resume Next
   WorkSheetExists = Not Worksheets(strName) Is Nothing
End Function

sub test_sheet()

 If Not WorkSheetExists("SheetName") Then
 MsgBox "Not available"
Else MsgBox "Available"
End If

End Sub
Филипп88
источник
1
    For Each Sheet In Worksheets
    If UCase(Sheet.Name) = "TEMP" Then
    'Your Code when the match is True
        Application.DisplayAlerts = False
        Sheet.Delete
        Application.DisplayAlerts = True
    '-----------------------------------
    End If
Next Sheet
Shrikant
источник
1

Измените "Данные" на любое имя листа, которое вы тестируете ...

On Error Resume Next 

Set DataSheet = Sheets("Data")

If DataSheet Is Nothing Then

     Sheets.Add(after:=ActiveSheet).Name = "Data"
     ''or whatever alternate code you want to execute''
End If

On Error GoTo 0
gth826a
источник
1

Без всяких сомнений, что указанная выше функция может работать, я только что получил следующий код, который работает очень хорошо:

Sub Sheet_exist ()
On Error Resume Next
If Sheets("" & Range("Sheet_Name") & "") Is Nothing Then
    MsgBox "doesnt exist"
Else
    MsgBox "exist"
End if
End sub

Примечание: Sheets_Nameздесь я прошу пользователя ввести имя, поэтому это может быть не то же самое для вас.

Макс Сегура
источник
0

Я сделал еще одну вещь: удалил лист только в том случае, если он существует - чтобы не получить ошибку, если его нет:

Excel.DisplayAlerts = False 
Dim WS
For Each WS In Excel.Worksheets
    If WS.name = "Sheet2" Then
        Excel.sheets("Sheet2").Delete
        Exit For
    End If
Next
Excel.DisplayAlerts = True
Шай Алон
источник
0

Я придумал простой способ сделать это, но не создавал для него новую сабвуфер. Вместо этого я просто «проверил» подпрограмму, над которой работал. Предположим, что имя листа, которое мы ищем, - «Sheet_Exist», и мы просто хотим активировать его, если он найден:

Dim SheetCounter As Integer

SheetCounter = 1

Do Until Sheets(SheetCounter).Name = "Sheet_Exist" Or SheetCounter = Sheets.Count + 1
 SheetCounter = SheetCounter +1
Loop
If SheetCounter < Sheets.Count + 1 Then
 Sheets("Sheet_Exist").Activate
Else
 MsgBox("Worksheet ""Sheet_Exist"" was NOT found")
End If

Я также добавил всплывающее окно, когда лист не существует.

imjordy23
источник
0

Я знаю, что это старый пост, но вот еще одно простое и быстрое решение.

Public Function worksheetExists(ByVal wb As Workbook, ByVal sheetNameStr As String) As Boolean

On Error Resume Next
worksheetExists = (wb.Worksheets(sheetNameStr).Name <> "")
Err.Clear: On Error GoTo 0

End Function
Гость
источник
0

Коротко и чисто:

Function IsSheet(n$) As Boolean
    IsSheet = Not IsError(Evaluate(n & "!a1"))
End Function
Герой Excel
источник
-4

На самом деле у меня был простой способ проверить, существует ли лист, а затем выполнить некоторую инструкцию:

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

Sub Foo ()

    Application.DisplayAlerts = False

    On Error GoTo instructions
    Sheets("NAME OF THE SHEET").Delete

    instructions:

    Sheets.Add After:=Sheets(Sheets.Count)
    ActiveSheet.Name = "NAME OF THE SHEET"

End Sub
Chenaou
источник
Проблема с этим ответом заключается в том, что после определения того, что лист действительно существует, он удаляется и, следовательно, больше не существует. Если бы это было написано как функция, оно могло бы иметь имя типа SheetExistsAfterDeletion и всегда возвращало бы FALSE.
ChrisB