本ブログでは、Excel&VBA解説サイト「エクセルの神髄」様出題の問題集、
「VBA100本ノック」に対する私の回答を順次公開しております。
この100本ノックに取り組むにあたり、
- 解答の際になるべく汎用関数を作り、各問題で共有する
というルールを設けております。
100番から逆順に解くという謎ルールでもやっており、
現在100~88までの解答が終わりました。
各解答ページには使った関数だけを載せていますが、
すべての汎用関数をまとめたモジュールも便利かと思い本ページに公開します。
モジュールごと個人用マクロブックに入れておき、
そのままドラッグ&ドロップでマクロファイルに入れるなどしてご活用ください。
100本ノックで使用した汎用関数集
Option Explicit ' FileSystemObjectの短縮取得 ' 参考:https://www.limecode.jp/entry/utility/shortcall-filesystemobject Public FSO As New FileSystemObject ' WorksheetFunctionの短縮取得 ' 参考:https://www.limecode.jp/entry/utility/shortcall-worksheetfunction Function Fx() As WorksheetFunction Set Fx = WorksheetFunction End Function ' UsedRangeのカット Function GetUsedRange指定行以下(対象シート As Worksheet, 指定行 As Long) As Range With 対象シート Set GetUsedRange指定行以下 = Intersect(.UsedRange, .Rows(指定行).Resize(.UsedRange.Rows.Count)) End With End Function ' 結合セル判定 ' 参考:https://www.limecode.jp/entry/syntax/check-mergecells-mergearea Function Is結合先頭セル(判定セル As Range) As Boolean Is結合先頭セル = (判定セル.MergeCells And 判定セル.Address = 判定セル.MergeArea.Cells(1, 1).Address) End Function Function Is結合内部セル(判定セル As Range) As Boolean Is結合内部セル = (判定セル.MergeCells And 判定セル.Address <> 判定セル.MergeArea.Cells(1, 1).Address) End Function Function Is結合セル全体(判定エリア As Range) As Boolean Is結合セル全体 = (判定エリア.MergeCells And 判定エリア.Address = 判定エリア.Cells(1, 1).MergeArea.Address) End Function ' 改行文字の置き換え ' 参考:https://www.limecode.jp/entry/syntax/linebreak-vbcrlf-vbcr-vblf Function 文中改行を指定文字に置き換える(元テキスト As String, Optional 置換テキスト As String = " ") As String Dim 結果テキスト As String 結果テキスト = Replace(元テキスト, vbCrLf, 置換テキスト) 結果テキスト = Replace(結果テキスト, vbCr, 置換テキスト) 結果テキスト = Replace(結果テキスト, vbLf, 置換テキスト) 文中改行を指定文字に置き換える = 結果テキスト End Function ' 指定行より下の削除 ' 参考:https://www.limecode.jp/entry/utility/delete-rows-below-to-last Sub 指定行より下をすべて削除する(対象シート As Worksheet, 指定行 As Long) With 対象シート Call フィルターをクリアする(対象シート) .Range(.Rows(指定行), .Rows(.Rows.Count)).Delete End With End Sub ' フィルターのクリア ' ◆ ブログ未掲載 Sub フィルターをクリアする(対象シート As Worksheet) If 対象シート.AutoFilterMode = True Then If 対象シート.AutoFilter.FilterMode = True Then 対象シート.AutoFilter.ShowAllData End If End If End Sub ' 最終行の取得 ' 参考:https://www.limecode.jp/entry/library/get-lastrow-lastcolumn Function Get最終行(指定オブジェクト As Variant, Optional ByVal C As Long = -1) As Long ' 渡されたオブジェクトからセル範囲を取得 Dim 対象セル範囲 As Range Select Case TypeName(指定オブジェクト) Case "Range" If 指定オブジェクト.Cells.CountLarge = 1 Then ' 単独セルにはCurrentRegionを取る Set 対象セル範囲 = 指定オブジェクト.CurrentRegion Else Set 対象セル範囲 = 指定オブジェクト End If Case "Worksheet" Set 対象セル範囲 = 指定オブジェクト.UsedRange Case "AutoFilter", "ListObject" Set 対象セル範囲 = 指定オブジェクト.Range Case Else Err.Raise 1000, , "対象外のオブジェクト「" & TypeName(指定オブジェクト) & "」が指定されました。" End Select ' エリアの最終行を取得 Get最終行 = 対象セル範囲.Rows.Count + 対象セル範囲.Row - 1 ' 列が指定されていればその列の入力最終行を取得 If C <> -1 Then Do While 対象セル範囲.Worksheet.Cells(Get最終行, C) = "" Get最終行 = Get最終行 - 1 If Get最終行 < 対象セル範囲.Row Then Get最終行 = 0 Exit Function End If Loop End If End Function ' 最終列の取得 ' 参考:https://www.limecode.jp/entry/library/get-lastrow-lastcolumn Function Get最終列(指定オブジェクト As Variant, Optional ByVal R As Long = -1) As Long ' 渡されたオブジェクトからセル範囲を取得 Dim 対象セル範囲 As Range Select Case TypeName(指定オブジェクト) Case "Range" If 指定オブジェクト.Cells.CountLarge = 1 Then ' 単独セルにはCurrentRegionを取る Set 対象セル範囲 = 指定オブジェクト.CurrentRegion Else Set 対象セル範囲 = 指定オブジェクト End If Case "Worksheet" Set 対象セル範囲 = 指定オブジェクト.UsedRange Case "AutoFilter", "ListObject" Set 対象セル範囲 = 指定オブジェクト.Range Case Else Err.Raise 1000, , "対象外のオブジェクト「" & TypeName(指定オブジェクト) & "」が指定されました。" End Select ' エリアの最終列を取得 Get最終列 = 対象セル範囲.Columns.Count + 対象セル範囲.Column - 1 ' 列が指定されていればその列の入力最終行を取得 If R <> -1 Then Do While 対象セル範囲.Worksheet.Cells(R, Get最終列) = "" Get最終列 = Get最終列 - 1 If Get最終列 < 対象セル範囲.Column Then Get最終列 = 0 Exit Function End If Loop End If End Function ' 行番号の検索 ' ◆ ブログ未掲載 Function Match行番号(ByVal 検索値 As Variant, 検索エリア As Range) As Long On Error Resume Next If IsDate(検索値) Then Dim x: x = CDbl(検索値) If Err.Number = 0 Then Match行番号 = Fx.Match(CDbl(検索値), 検索エリア, 0) + 検索エリア.Row - 1 Exit Function End If End If Match行番号 = Fx.Match(検索値, 検索エリア, 0) + 検索エリア.Row - 1 End Function ' 列番号の検索 ' ◆ ブログ未掲載 Function Match列番号(ByVal 検索値 As Variant, 検索エリア As Range) As Long On Error Resume Next If IsDate(検索値) Then Match列番号 = Fx.Match(CDbl(検索値), 検索エリア, 0) + 検索エリア.Column - 1 Else Match列番号 = Fx.Match(検索値, 検索エリア, 0) + 検索エリア.Column - 1 End If End Function ' データ件数 ' ◆ ブログ未掲載 Function Countデータ件数(対象シート As Worksheet) As Long If 対象シート.AutoFilterMode = False Then Exit Function With 対象シート.AutoFilter.Range Countデータ件数 = .Rows.Count + .Row - 2 End With End Function ' 各列のデータ部分 ' 参考:https://www.limecode.jp/entry/utility/get-column-data-range Function GetRange指定列のデータ部分(対象シート As Worksheet, 対象列 As Long) As Range If Countデータ件数(対象シート) = 0 Then Exit Function Set GetRange指定列のデータ部分 = 対象シート.Cells(対象シート.AutoFilter.Range.Row + 1, 対象列) _ .Resize(Countデータ件数(対象シート)) End Function ' フィルターデータ部 ' 参考:https://www.limecode.jp/entry/utility/get-autofilter-datarange Function GetRangeフィルターデータ部分(指定シート As Worksheet) As Range If 指定シート.AutoFilterMode = False Then Exit Function Dim フィルターデータ部 As Range Set フィルターデータ部 = 指定シート.AutoFilter.Range If フィルターデータ部.Rows.Count = 1 Then Exit Function Set フィルターデータ部 = フィルターデータ部.Offset(1) Set フィルターデータ部 = フィルターデータ部.Resize(フィルターデータ部.Rows.Count - 1) Set GetRangeフィルターデータ部分 = フィルターデータ部 End Function ' エリアの拡大縮小 ' 参考:https://www.limecode.jp/entry/utility/expand-range Function Resizeエリアの拡大縮小(指定エリア As Range, Optional R上方向 As Long = 0, Optional R下方向 As Long = 0 _ , Optional C左方向 As Long = 0, Optional C右方向 As Long = 0) As Range On Error Resume Next With 指定エリア Set Resizeエリアの拡大縮小 = .Resize(.Rows.Count + R上方向 + R下方向, .Columns.Count + C左方向 + C右方向) End With Set Resizeエリアの拡大縮小 = Resizeエリアの拡大縮小.Offset(-R上方向, -C左方向) End Function ' 不要行の削除 ' 参考:https://www.limecode.jp/entry/utility/delete-rows-quickly Sub 指令列がTRUEの行を高速削除する(データエリア全体 As Range, 判定列 As Long) Dim ws対象シート As Worksheet: Set ws対象シート = データエリア全体.Worksheet Dim column判定列 As Range Set column判定列 = Intersect(データエリア全体, ws対象シート.Columns(判定列)) If column判定列 Is Nothing Then Exit Sub Dim RCount削除行数 As Long RCount削除行数 = Fx.CountIf(column判定列, True) If RCount削除行数 = 0 Then Exit Sub ' ソートしてTRUEを1エリアにまとめる データエリア全体.Sort ws対象シート.Cells(1, 判定列) ' 第1TRUE行から削除行数分を削除 Dim R1st削除開始行 As Long R1st削除開始行 = Match行番号(True, column判定列) ws対象シート.Rows(R1st削除開始行).Resize(RCount削除行数).Delete End Sub ' 値のコピー ' 参考:https://www.limecode.jp/entry/syntax/rangecopy-pastevalues Sub 値をコピーする(コピー元基準セルまたはエリア As Range, ペースト基準セル As Range _ , Optional ByVal エリア高 As Long = -1, Optional ByVal エリア幅 As Long = -1) ' ◇ エリアサイズの省略時は、コピーエリアのサイズを取得 If エリア高 = -1 Then エリア高 = コピー元基準セルまたはエリア.Rows.Count If エリア幅 = -1 Then エリア幅 = コピー元基準セルまたはエリア.Columns.Count ' 値をコピー ペースト基準セル.Resize(エリア高, エリア幅).Value = コピー元基準セルまたはエリア.Resize(エリア高, エリア幅).Value End Sub ' シート数式計算 ' 参考:https://www.limecode.jp/entry/syntax/formula Sub シート数式で計算する(計算エリア As Range, シート数式 As String) 計算エリア.Formula = シート数式 計算エリア.Value = 計算エリア.Value End Sub ' 文字列検索切り出しLeft/Right/Mid ' 参考:https://www.limecode.jp/entry/library/string-manipulation Function Left文字列まで(ByVal 元テキスト As String, ByVal 検索値 As String _ , Optional is検索値を結果に含む As Boolean = False) As String Dim instr位置 As Long: instr位置 = InStr(元テキスト, 検索値) If instr位置 > 0 Then Left文字列まで = Left(元テキスト, instr位置 - 1) & IIf(is検索値を結果に含む, 検索値, "") End If End Function Function Right文字列まで(ByVal 元テキスト As String, ByVal 検索値 As String _ , Optional is検索値を結果に含む As Boolean = False) As String Dim instrRev位置 As Long: instrRev位置 = InStrRev(元テキスト, 検索値) If instrRev位置 > 0 Then Right文字列まで = IIf(is検索値を結果に含む, 検索値, "") _ & Mid(元テキスト, instrRev位置 + Len(検索値)) End If End Function Function Mid文字列から文字列(ByVal 元テキスト As String, ByVal 前検索値 As String, ByVal 後検索値 As String _ , Optional is前検索値を結果に含む As Boolean = False, Optional is後検索値を結果に含む As Boolean = False) As String Dim instr前値 As Long: instr前値 = InStr(元テキスト, 前検索値) If instr前値 = 0 Then Exit Function Dim instr後値 As Long: instr後値 = InStr(instr前値 + Len(前検索値) + 1, 元テキスト, 後検索値) If instr後値 = 0 Then Exit Function Mid文字列から文字列 = _ IIf(is前検索値を結果に含む, 前検索値, "") & _ Mid(元テキスト, instr前値 + Len(前検索値), instr後値 - instr前値 - Len(前検索値)) & _ IIf(is後検索値を結果に含む, 後検索値, "") End Function ' RGB⇔HTMLカラーコード相互変換 ' 参考:https://www.limecode.jp/entry/utility/convert-rgb-html-colorcode Function ConvRGB値→HTMLカラーコード(RGB値 As Long) As String Dim RGBHex値 As String RGBHex値 = Right("000000" & Hex(RGB値), 6) ConvRGB値→HTMLカラーコード = Right(RGBHex値, 2) _ & Mid(RGBHex値, 3, 2) _ & Left(RGBHex値, 2) End Function Function ConvHTMLカラーコード→RGB値(HTMLカラーコード As String) As Long ConvHTMLカラーコード→RGB値 = RGB("&H" & Left(HTMLカラーコード, 2) _ , "&H" & Mid(HTMLカラーコード, 3, 2) _ , "&H" & Right(HTMLカラーコード, 2)) End Function ' 配列の要素数の取得 ' 参考:https://www.limecode.jp/entry/syntax/ubound-lbound-count-array-elemens Function Count配列の要素数(Arr, Optional 次元 = 1) As Long Count配列の要素数 = UBound(Arr, 次元) - LBound(Arr, 次元) + 1 End Function ' 配列の次元数の取得 ' 参考:https://www.limecode.jp/entry/utility/get-array-dimension Function Get配列の次元数(Arr As Variant) As Long ' 渡された変数が配列ではない場合は0を返すこととする If IsArray(Arr) = False Then Get配列の次元数 = 0: Exit Function ' エラーが出るまでUBoundを取得してみる Dim tmp Dim 次元数 As Long: 次元数 = 0 On Error Resume Next Do While Err.Number = 0 次元数 = 次元数 + 1 tmp = UBound(Arr, 次元数) Loop On Error GoTo 0 ' エラーが出たひとつ前の次元が求める次元数 Get配列の次元数 = 次元数 - 1 End Function ' 一次元配列 → セル ' 参考:https://www.limecode.jp/entry/utility/output-array-to-range Sub 一次元配列をセルに出力する(出力始点セル As Range, Arr出力配列 As Variant _ , Optional is縦方向へ出力 As Boolean = True) Dim 要素数 As Long: 要素数 = Count配列の要素数(Arr出力配列) If is縦方向へ出力 Then 出力始点セル.Resize(要素数, 1).Value _ = GetArray一次元配列→n行1列の二次元配列(Arr出力配列) Else 出力始点セル.Resize(1, 要素数).Value = Arr出力配列 End If End Sub ' 二次元配列 → セル ' 参考:https://www.limecode.jp/entry/utility/output-array-to-range Sub 二次元配列をセルに出力する(出力始点セル As Range, Arr出力配列 As Variant) 出力始点セル.Resize(Count配列の要素数(Arr出力配列, 1) _ , Count配列の要素数(Arr出力配列, 2)).Value = Arr出力配列 End Sub ' Transpose上限対応用関数 ' 参考:https://www.limecode.jp/entry/utility/output-array-to-range Function GetArray一次元配列→n行1列の二次元配列(Arr As Variant) As Variant Dim 生成配列() ReDim 生成配列(LBound(Arr) To UBound(Arr), 1 To 1) Dim i As Long For i = LBound(Arr) To UBound(Arr) 生成配列(i, 1) = Arr(i) Next GetArray一次元配列→n行1列の二次元配列 = 生成配列 End Function ' 配列を新規シートに出力する ' 参考:https://www.limecode.jp/entry/debug/display-array-on-newsheet Sub 配列を新規シートに出力する(Arr) Workbooks.Add.Worksheets(1).Range("A1") _ .Resize(Count配列の要素数(Arr, 1), Count配列の要素数(Arr, 2)) = Arr End Sub ' Dictionary(Item:配列) → セル ' 参考:https://www.limecode.jp/entry/utility/convert-jagarray-to-2d-array Sub Itemが一次元配列のDictionaryをセルに出力する(出力始点セル As Range, Dic As Dictionary) Dim Arr: Arr = GetArr二次元配列←ジャグ配列(Dic.Items) Call 二次元配列をセルに出力する(出力始点セル, Arr) End Sub ' 二次元配列←ジャグ配列 ' 参考:https://www.limecode.jp/entry/utility/convert-jagarray-to-2d-array Function GetArr二次元配列←ジャグ配列(Arrジャグ配列 As Variant) As Variant Dim i As Long, j As Long ' ジャグ配列のインデックス Dim R As Long, C As Long ' 二次元配列のインデックス Dim Arr出力配列() Dim 最大要素数 As Long: 最大要素数 = 0 ' 配列内の配列の中で最も大きい要素数を取得 For i = LBound(Arrジャグ配列) To UBound(Arrジャグ配列) Dim 現要素数 As Long: 現要素数 = Count配列の要素数(Arrジャグ配列(i)) If 現要素数 >= 最大要素数 Then 最大要素数 = 現要素数 Next ' 出力二次元配列を準備 ReDim Arr出力配列(1 To Count配列の要素数(Arrジャグ配列), 1 To 最大要素数) ' 全要素を代入 R = 1 For i = LBound(Arrジャグ配列) To UBound(Arrジャグ配列) C = 1 For j = LBound(Arrジャグ配列(i)) To UBound(Arrジャグ配列(i)) If IsObject(Arrジャグ配列(i)(j)) Then Set Arr出力配列(R, C) = Arrジャグ配列(i)(j) Else Let Arr出力配列(R, C) = Arrジャグ配列(i)(j) End If C = C + 1 Next R = R + 1 Next GetArr二次元配列←ジャグ配列 = Arr出力配列 End Function ' セルのリストを1次元配列に ' 参考:https://www.limecode.jp/entry/utility/getarray-from-rangeobject Function GetArrayセルのリストを1次元配列に変換する(セルリスト As Range) As Variant ' ◇ 単セル → 値そのまま If セルリスト.Cells.Count = 1 Then GetArrayセルのリストを1次元配列に変換する = Array(セルリスト.Value) Exit Function End If ' 1列データの時はTransposeで高速化 If セルリスト.Areas.Count = 1 And セルリスト.Columns.Count = 1 And セルリスト.Count <= 65535 Then GetArrayセルのリストを1次元配列に変換する = Fx.Transpose(セルリスト) Exit Function End If ' それ以外は1セルずつ値を格納 Dim Arr生成配列() As Variant ReDim Arr生成配列(1 To セルリスト.Cells.Count) As Variant Dim i As Long: i = 1 Dim Cell As Range For Each Cell In セルリスト.Cells Arr生成配列(i) = Cell.Value i = i + 1 Next GetArrayセルのリストを1次元配列に変換する = Arr生成配列 End Function ' Dictionaryを新規シートに出力する ' 参考:https://www.limecode.jp/entry/debug/display-dictionary-on-newsheet Sub Dictionaryを新規シートに出力する(Dic As Dictionary) With Workbooks.Add.Worksheets(1) Call 一次元配列をセルに出力する(.Range("A1"), Dic.Keys) Call 一次元配列をセルに出力する(.Range("B1"), Dic.Items) End With End Sub ' シートをファイル分割 ' ◆ ブログ未掲載 Function シートを要素ごとにファイル分割する(ws対象シート As Worksheet, 分割対象列 As Long, 見出し行 As Long _ , Path出力先フォルダ As String, ブック名接頭部 As String) As Worksheet ' テンプレートシートを作成 ws対象シート.Copy Dim wsテンプレート As Worksheet: Set wsテンプレート = ActiveSheet wsテンプレート.Name = "wsテンプレート" Call 指定行より下をすべて削除する(wsテンプレート, 見出し行 + 1) ' 対象シートのコピーを作成 ws対象シート.Copy Dim wsコピー元データ As Worksheet Set wsコピー元データ = ActiveSheet wsコピー元データ.Name = "wsコピー元データ" ' コピー元データの見出し行より下を分割対象列でソート GetUsedRange指定行以下(wsコピー元データ, 見出し行 + 1).Sort wsコピー元データ.Cells(1, 分割対象列) ' データエリアを走査 Dim R_コピー開始行 As Long: R_コピー開始行 = 見出し行 + 1 Dim R_コピー最終行 As Long Dim R As Long For R = 見出し行 + 2 To Get最終行(wsコピー元データ) ' 対象列の要素が切り替わったタイミングでシートを複製 If wsコピー元データ.Cells(R, 分割対象列) <> wsコピー元データ.Cells(R + 1, 分割対象列) _ Or R = Get最終行(wsコピー元データ) Then R_コピー最終行 = R Dim ws分割シート As Worksheet wsテンプレート.Copy Set ws分割シート = ActiveSheet Range(wsコピー元データ.Rows(R_コピー開始行), wsコピー元データ.Rows(R_コピー最終行)) _ .Copy ws分割シート.Cells(見出し行 + 1, 1) ws分割シート.Parent.SaveAs Path出力先フォルダ & "\" & ブック名接頭部 & "(" & wsコピー元データ.Cells(R, 分割対象列) & ").xlsx" ws分割シート.Parent.Close False R_コピー開始行 = R + 1 R_コピー最終行 = 0 End If Next wsコピー元データ.Parent.Close False wsテンプレート.Parent.Close False End Function ' フォルダ内ファイルの結合 ' 参考:https://www.limecode.jp/entry/tools/merge-all-workbooks-in-folder Function 指定フォルダ内のすべてのブックを結合する _ (Path指定フォルダ As String, R_見出し行 As Long _ , Optional ByVal ファイルLike条件 As String = "*", Optional 対象拡張子 As String = "xlsx" _ , Optional ByVal シート名Like条件 As String = "*" _ , Optional ファイル名出力始点セル As Range, Optional 読込結果出力始点セル As Range) As Worksheet ' 対象フォルダを取得 If FSO.FolderExists(Path指定フォルダ) = False Then Exit Function Dim 対象フォルダ As Folder Set 対象フォルダ = FSO.GetFolder(Path指定フォルダ) If 対象フォルダ.Files.Count = 0 Then Exit Function ' 出力するシートは第1ブックの第1シートを利用 Dim ws出力シート As Worksheet ' Like条件テキストを生成 ファイルLike条件 = ファイルLike条件 & "." & 対象拡張子 ' ファイルの走査ログを出力する各セルをSet Dim ファイル名出力セル As Range: Set ファイル名出力セル = ファイル名出力始点セル Dim 読込結果出力セル As Range: Set 読込結果出力セル = 読込結果出力始点セル ' 指定フォルダ内のすべてのファイルを走査 Dim 読取結果テキスト As String Dim ファイル As File For Each ファイル In 対象フォルダ.Files 読取結果テキスト = "" ' 条件を満たすファイルを処理 If ファイル.Name Like ファイルLike条件 Then Call 対象ブック内のすべてのシートを取り込む(ファイル.Path, ws出力シート _ , R_見出し行, シート名Like条件, 読取結果テキスト) Else 読取結果テキスト = "ファイル名条件に合致せず" End If ' 読取ログの出力 If Not ファイル名出力セル Is Nothing Then ファイル名出力セル.Value = ファイル.Name Set ファイル名出力セル = ファイル名出力セル.Offset(1) End If If Not 読込結果出力セル Is Nothing Then 読込結果出力セル.Value = 読取結果テキスト Set 読込結果出力セル = 読込結果出力セル.Offset(1) End If Next ' 指定フォルダ内のすべてのファイルを走査 Set 指定フォルダ内のすべてのブックを結合する = ws出力シート End Function ' ブックごとの取込処理 Private Sub 対象ブック内のすべてのシートを取り込む(ファイルパス As String, ws出力シート As Worksheet _ , R_見出し行 As Long, シート名Like条件 As String, ByRef 読取結果テキスト As String) ' ファイルを開く Dim wb読取ブック As Workbook: Set wb読取ブック = Nothing On Error Resume Next Set wb読取ブック = Workbooks.Open(ファイルパス) On Error GoTo 0 If wb読取ブック Is Nothing Then 読取結果テキスト = "ブックがエラーで開けませんでした。" Exit Sub End If ' 開いたブック内の条件合致シートをループ Dim cnt読取シート数 As Long: cnt読取シート数 = 0 Dim ws読取シート As Worksheet For Each ws読取シート In wb読取ブック.Worksheets If ws読取シート.Name Like シート名Like条件 Then ' 最初に読み取ったシートをコピーして出力シートとして使う If ws出力シート Is Nothing Then ws読取シート.Copy Set ws出力シート = ActiveSheet cnt読取シート数 = cnt読取シート数 + 1 Else ' UsedRangeのうち見出し行より下を取得 Dim コピーエリア As Range Set コピーエリア = GetUsedRange指定行以下(ws読取シート, R_見出し行 + 1) ' コピーを実行 If Not コピーエリア Is Nothing Then コピーエリア.Copy ws出力シート.Cells(Get最終行(ws出力シート) + 1, コピーエリア.Column) cnt読取シート数 = cnt読取シート数 + 1 End If End If End If Next ' 開いたブック内の条件合致シートをループ 読取結果テキスト = cnt読取シート数 & "枚のシートを取込" wb読取ブック.Close False End Sub ' 新規フォルダ作成(連番付) ' 参考:https://www.limecode.jp/entry/utility/mkdir-addserialnumber Function 連番を付与して新規フォルダを作成する(Path親フォルダ As String, 作成フォルダ名 As String _ , Optional is第1フォルダにも1を付番する As Boolean = False) As String ' 連番なしのフォルダパス Dim path作成フォルダベース As String path作成フォルダベース = Path親フォルダ & "\" & 作成フォルダ名 ' 実際に作成するフォルダパス Dim path作成フォルダ As String If is第1フォルダにも1を付番する Then path作成フォルダ = path作成フォルダベース & "-1" Else path作成フォルダ = path作成フォルダベース End If ' 第1フォルダがなければ作成してExit If Dir(path作成フォルダ, vbDirectory) = "" Then MkDir path作成フォルダ 連番を付与して新規フォルダを作成する = path作成フォルダ Exit Function End If ' フォルダの無い番号まで連番を進める Dim i As Long: i = 2 Do While Dir(path作成フォルダベース & "-" & i, vbDirectory) <> "" i = i + 1 Loop ' フォルダを作成 path作成フォルダ = path作成フォルダベース & "-" & i MkDir path作成フォルダ 連番を付与して新規フォルダを作成する = path作成フォルダ End Function ' 自動更新の停止 Sub エクセルの自動更新を停止する(isブック計算をOFFに As Boolean _ , Optional is画面更新をOFFに As Boolean = True _ , Optional isイベントをOFFに As Boolean = True) If isブック計算をOFFに Then Application.Calculation = xlCalculationManual If is画面更新をOFFに Then Application.ScreenUpdating = False If isイベントをOFFに Then Application.EnableEvents = False End Sub ' 自動更新の開始 Sub エクセルの自動更新を開始する() With Application .Calculation = xlCalculationAutomatic .ScreenUpdating = True .EnableEvents = True .StatusBar = False .DisplayAlerts = True End With End Sub ' Accessテーブルの取込 ' 参考:https://www.limecode.jp/entry/utility/export-access-table-to-worksheet Sub Accessの指定テーブルをセルに出力する(Accessファイルパス As String, テーブル名 As String _ , 出力起点セル As Range, is見出しも出力する As Boolean) Dim 接続 As Object: Set 接続 = CreateObject("ADODB.Connection") 接続.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & Accessファイルパス & ";" Dim レコードセット As Object: Set レコードセット = CreateObject("ADODB.Recordset") レコードセット.Open "SELECT * FROM " & テーブル名, 接続 ' フィールド名を第1行に出力 If is見出しも出力する Then Dim C As Long For C = 1 To レコードセット.Fields.Count 出力起点セル.Cells(1, C).Value = レコードセット.Fields(C - 1).Name Next End If ' 第2行以降に全レコードを出力 出力起点セル.Cells(IIf(is見出しも出力する, 2, 1), 1).CopyFromRecordset レコードセット レコードセット.Close: Set レコードセット = Nothing 接続.Close: Set 接続 = Nothing End Sub ' QueryTableによるWEB読み込みの汎用関数 ' 参考:https://www.limecode.jp/entry/utility/querytables-import-web-table Sub QueryTableでWEB上の表を読み込む(出力起点セル As Range _ , 対象URL As String, Optional テーブルNo As Long = -1 _ , Optional is書式リンク含む As Boolean = False, Optional is日付に変換する As Boolean = False) With 出力起点セル.Worksheet.QueryTables.Add("URL;" & 対象URL, 出力起点セル) If テーブルNo = -1 Then ' テーブルNo省略時は全テーブルを対象 .WebSelectionType = xlAllTables Else .WebTables = xlSpecifiedTables .WebTables = テーブルNo End If .WebFormatting = IIf(is書式リンク含む, xlWebFormattingAll, xlWebFormattingNone) .WebDisableDateRecognition = Not (is日付に変換する) .Refresh BackgroundQuery:=False .Delete End With End Sub