测试或检查工作表是不是存在
Posted
技术标签:
【中文标题】测试或检查工作表是不是存在【英文标题】:Test or check if sheet exists测试或检查工作表是否存在 【发布时间】:2011-10-05 00:17:56 【问题描述】: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
【问题讨论】:
Excel VBA If WorkSheet("wsName") Exists的可能重复 【参考方案1】:有些人不喜欢这种方法,因为“不恰当”地使用错误处理,但我认为它在 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
【讨论】:
完全适合使用 IMO。对于假定存在但不存在且历史悠久的事物来说,这是一个陷阱 - cf perl strict、STAE 等。赞成 应该使用ActiveWorkbook
而不是ThisWorkbook
。后者指的是包含宏代码的工作簿,它可能与想要测试的工作簿不同。我猜ActiveWorkbook
在大多数情况下都很有用(不过,人为的情况总是可用的)。
sht Is Nothing
将是 True
如果没有具有该名称的工作表,但如果存在 is 具有该名称的工作表,我们希望返回 True
,因此不是。如果您重新安排一点到SheetExists = sht Is Not Nothing
,它会更容易一些(但无效)
请注意,如果您在个人宏工作簿中运行此代码,请将 If wb Is Nothing Then Set wb = ThisWorkbook
更改为 If wb Is Nothing Then Set wb = ActiveWorkbook
这是一种高效的方法(请参阅下面 Rory 回答下的基准测试我的 cmets),所以谁在乎批评者的想法。请注意(截至目前)您的反对票为零。【参考方案2】:
如果您只对工作表特别感兴趣,可以使用简单的 Evaluate 调用:
Function WorksheetExists(sName As String) As Boolean
WorksheetExists = Evaluate("ISREF('" & sName & "'!A1)")
End Function
【讨论】:
@Rory 我对此与蒂姆威廉姆斯的回答进行了一些基准测试。超过 500,000 次循环,你的用时 22 秒,而蒂姆的用时 @roryap - 如果您需要运行 500,000 次,您需要重新考虑您的整个方法。 ;) @roryap - 但是,使用几种缓慢的方法会开始累积秒数。我会说这是非常有价值的信息,因为 Excel“应用程序”开始使用各种 Range 方法等很容易地运行几秒钟。 @roryap - 信息对对话有何价值?我只是说在代码周围分散低效的方法会使整个应用程序变慢。你测试这 500k 次太棒了,我感谢你这样做,22 秒不是很好。 (我同意你的观点) 即使速度较慢,它看起来也比公认的答案更干净。来自我的 +1。【参考方案3】:您不需要错误处理来完成此操作。您所要做的就是遍历所有工作表并检查指定的名称是否存在:
Dim exists As Boolean
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
【讨论】:
【参考方案4】:由于检查集合的成员是一个普遍的问题,这里是@Tim 答案的抽象版本:
Function Contains(objCollection As Object, strName as String) As Boolean
Dim o as Object
On Error Resume Next
set o = objCollection(strName)
Contains = (Err.Number = 0)
Err.Clear
End Function
此函数可用于任何集合,如对象(Shapes
、Range
、Names
、Workbooks
等)。
要检查工作表是否存在,请使用If Contains(Sheets, "SheetName") ...
【讨论】:
这不会捕获集合中的原始类型,因为Set
关键字会引发错误。我发现不是使用Set
,而是要求集合成员的TypeName
适用于所有情况,即TypeName objCollection(strName)
@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
【参考方案5】:
更正: 没有错误处理:
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
【讨论】:
【参考方案6】:这是我写的:
Function sheetExist(sSheet As String) As Boolean
On Error Resume Next
sheetExist = (ActiveWorkbook.Sheets(sSheet).Index > 0)
End Function
【讨论】:
很棒的功能!不仅速度快,而且最简洁。 我相信这是最符合问题的答案 我喜欢这个。请注意,它依赖于 sheetExist 的默认值为 False 的事实,因为它是一个布尔函数。如果工作表不存在,赋值语句实际上不会为 sheetExist 分配 False 值,它只是出错并保留默认值。如果你愿意,你可以依赖这样一个事实,即分配给布尔变量的任何非零值都会给出 True 结果并省略 > 0 比较,如下所示:sheetExist = ActiveWorkbook.Sheets(sSheet).Index
【参考方案7】:
如果有人想避免使用 VBA 并测试工作表是否纯粹存在于单元格公式中,则可以使用 ISREF
和 INDIRECT
函数:
=ISREF(INDIRECT("SheetName!A1"))
如果工作簿包含名为 SheetName
的工作表,则返回 TRUE
,否则返回 FALSE
。
【讨论】:
【参考方案8】:紧凑的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"
更多信息:
MSDN :For Each
…Next
Statement (VBA)
MSDN:Exit
Statement (VBA)
MSDN:Comparison Operators (VBA)
【讨论】:
【参考方案9】:我的解决方案看起来很像 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
.
【讨论】:
【参考方案10】:晚了很多年,但我只是需要这样做并且不喜欢发布的任何解决方案......所以我做了一个,这一切都归功于(海绵宝宝彩虹手势)“Evaluate()”的魔力!
Evaluate("IsError(" & vSheetName & "!1:1)")
如果 Sheet 不存在,则返回 TRUE;如果工作表确实存在,则为 FALSE。 您可以将任何您喜欢的范围替换为“1:1”,但我建议不要使用单个单元格,因为如果它包含错误(例如,#N/A),它将返回 True。
【讨论】:
我在代码中看到 2 个错误:(1)如果工作表存在,则会出现错误 13,因为1:1
(2)如果工作表名称包含空格并且存在,则代码返回 False。为了避免#N/A 问题,我使用了 CELL 函数。这对我有用:Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))")
如果工作表不存在,则在此处退出子:If Evaluate("IsError(Cell(""col"",'" + vSheetName + "'!A1))") Then Exit Sub
【参考方案11】:
将测试放在一个函数中,您将能够重用它,并且您具有更好的代码可读性。
不要使用“On Error Resume Next”,因为它可能与您代码的其他部分发生冲突。
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
【讨论】:
【参考方案12】:短而干净:
Function IsSheet(n$) As Boolean
IsSheet = Not IsError(Evaluate("'" & n & "'!a1"))
End Function
【讨论】:
【参考方案13】:为什么不只使用一个小循环来确定命名的工作表是否存在?假设您正在当前打开的工作簿中查找名为“Sheet1”的工作表。
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
【讨论】:
【参考方案14】: 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
【讨论】:
【参考方案15】:如果您是WorksheetFunction.
的粉丝,或者您在非英语国家/地区工作且使用非英语 Excel,这是一个很好的解决方案,非常有效:
WorksheetFunction.IsErr(Evaluate("'" & wsName & "'!A1"))
或者在这样的函数中:
Function WorksheetExists(sName As String) As Boolean
WorksheetExists = Not WorksheetFunction.IsErr(Evaluate("'" & sName & "'!A1"))
End Function
【讨论】:
【参考方案16】: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
【讨论】:
【参考方案17】:将“数据”更改为您要测试的任何工作表名称...
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
【讨论】:
【参考方案18】:毫无疑问,上面的函数可以工作,我刚刚得到了下面的代码,它工作得很好:
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
是我要求用户输入名称的地方,所以这对你来说可能不一样。
【讨论】:
【参考方案19】:我做了另一件事:仅当工作表存在时才删除工作表 - 如果不存在则不会出错:
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
【讨论】:
【参考方案20】:如果需要,我使用此函数检查并返回新的工作表名称。 WSname 是所需的工作表名称,而 WBCur 是您要签入的工作簿。我使用它是因为不需要错误处理,并且可以在创建新工作表时调用它。
Public Function CheckNewWorksheetName(WSName As String, WBCur As Workbook) 'Will return New Name if needed
Dim NewWSNum As Long, A As Integer, B As Integer, WorksheetFound As Boolean
NewWSNum = 1
WorksheetFound = False
For A = 1 To WBCur.Worksheets.Count
If WBCur.Worksheets(A).Name = WSName Then
A = WBCur.Worksheets.Count
WorksheetFound = True
End If
Next A
If WorksheetFound = False Then
CheckNewWorksheetName = WSName
Else
Do While WorksheetFound = True
WorksheetFound = False
For B = 1 To WBCur.Worksheets.Count
If WBCur.Worksheets(B).Name = WSName & "_" & NewWSNum Then
B = WBCur.Worksheets.Count
WorksheetFound = True
NewWSNum = NewWSNum + 1
End If
Next B
Loop
CheckNewWorksheetName = WSName & "_" & NewWSNum
End If
End Function
【讨论】:
【参考方案21】:我想出了一个简单的方法来做到这一点,但我没有为它创建一个新的子。相反,我只是在我正在研究的潜艇中“进行了检查”。假设我们要查找的工作表名称是“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
当工作表不存在时,我还添加了一个弹出窗口。
【讨论】:
【参考方案22】:我知道这是一篇旧帖子,但这是另一个快速的简单解决方案。
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
【讨论】:
【参考方案23】:我其实有一个简单的方法来检查工作表是否存在,然后执行一些指令:
在我的情况下,我想删除工作表,然后重新创建具有相同名称的同一个工作表,但如果程序无法删除工作表,因为它已经被删除,代码就会中断
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
【讨论】:
这个答案的问题是,在确定工作表确实存在时,它被删除,因此不再存在。如果这被写成一个函数,它可能有一个像 SheetExistsAfterDeletion 这样的名字,并且总是返回 FALSE。以上是关于测试或检查工作表是不是存在的主要内容,如果未能解决你的问题,请参考以下文章