Excel VBAでシートの存在有無を判定するのにループはいらない。On Errorステートメントを使おう

Excel VBAでシートの存在有無を判定する場合にループ使うのは冗長だなーと思ったのだが、実はOn Errorステートメントを使うとすっきりと書けた、という話。

元ネタはExcel VBA If WorkSheet(“wsName”) Exists - Stack Overflow

本論

Excel VBAでシートが存在するかどうか判定しくて調べていたのだが、日本語で検索するとSheetsWorksheetsをループするサンプルがよく出てくる*1

ただ、これらのサンプルはあるシートの存在有無を確認するために、ループで全部のシートをなめるので無駄な処理だ。

どうにかならないものかと英語でぐぐったらStack Overflowに綺麗な解決策があった。

以下はExcel VBA If WorkSheet(“wsName”) Exists - Stack OverflowにおけるTim Williamさんの回答

Function SheetExists(SheetName As String, Optional wb As Excel.Workbook)
   Dim s As Excel.Worksheet
   If wb Is Nothing Then Set wb = ThisWorkbook
   On Error Resume Next
   Set s = wb.Sheets(SheetName)
   On Error GoTo 0
   SheetExists = Not s Is Nothing
End Function

SheetNameのシートが存在しない場合に、あえてエラーを発生させた上でOn Errorステートメントを使って値を取得しないままとしているのが肝。

  • 存在する場合は普通に処理が進んだ結果、変数sに値が入るので戻り値のNot s Is NothingはTrueに、

  • 存在しない場合は、wb.Sheets(SheetName)がエラーになるが、On Error Resume Nextが有効なので次の処理へ変数sが空のまま次の処理へ進み、戻り値のNot s Is Nothingはfalseになるというわけ

こんな風にOn Error Resume Nextの後、即座にOn Error GoTo 0で無効化するパターンは応用が利きそうな気がする。 難しいコードではないのだけれど、まったく思いつかなかった。

Tim Williamさんすごい

参考
追記

5/24追記:投稿した内容のライセンスは? - ヘルプ センター - スタック・オーバーフローにも記載がある通り、Stack Overflow上の記事はCreative Commons Attribution-Share Alike でライセンスされている*2*3。なのでこの記事もライセンスに従って継承しCC-BY-SAとします(引用要件を満たしているかも微妙なので)。