Excelの元ファイルから特定のシートを選定して新しいExcelbookを作成する。

■総合的な目的の前提(以下の内容を網羅するExcelマクロ) 以下のような条件を想定して作ったExcelマクロです

前提

●元ファイルから、特定のシートを選択して新しいExcelファイルを作成する
●元ファイルには、一切の変更を加えない
●元ファイルの指定は、該当のファイル、個人用マクロブックどちらからでも実行可能
⇒アクティブになっているExcelファイルを対象元として扱う

●保存先は、元ファイルの同一階層フォルダ。
⇒保存前で元フォルダのパスが無い時(保存されてない場合)はドキュメントフォルダに保存
⇒ドキュメントフォルダは、パブリックではなくサインイン中のユーザーフォルダ

●書き出し先ファイルは、マクロ内上部の指定箇所で管理しやすい
●特定のシート選択は、マクロ内上部の指定箇所で管理しやすい

想定条件

●元ファイルには、シート毎に相互に参照設定が施されている
●書き出し先と、元ファイルの中で参照がされている場合は、値で書出して参照させない
●書出し先内(シートどうし)で参照設定されている場合は、そのままにする
●書出し先のシートでの入力規制(リストからのプルダウン等)は解除しない
●書出し先のシートに、フィルタ設定がされていても、解除しない

限定的な条件

●複数のパターンセットが考えられるので、Privateでマクロを隠さない
●後から管理が面倒(呼出し元の不明など)にならないように、Functionは使わない
●1モジュール内に、1プロシージャで書ける様に記述する
●プロシージャ内のsubや、コピーするシート、書出しファイル名だけの書き換えで管理する

良ければ以下をコピーして使ってみてください。部分的にコピペでも効果的に使えると思います。(不要な行やコメントアウトは適宜削除して使ってください)

Option Explicit

‘=================================================
‘ 目的:
‘ アクティブなブック(= コピー元 / 元ファイル)から、
‘ 指定したシートのみを新規ブックとしてコピーし、
‘ 参照状態を下記ルールで整理して保存する。

‘ 【参照整理ルール】
‘ 1) コピー先シート同士の参照は維持(外部参照 → 内部参照へ置換)
‘ 例)=[元ファイル.xlsm]Sheet10!C8 → =Sheet10!C8 (式は保持)

‘ 2) コピー先以外のシート・元ファイルへの参照は値確定
‘ c.Value = c.Value により、数式 → 値へ変換(入力規則・フィルタは維持)

‘ 3) セル外に残る外部リンク(定義名/グラフ/検証のリスト参照等)は
‘ BreakLink により、元ファイルへの依存を完全排除

‘ 【保存先ルール】
‘ – 原則:元ファイルと同じフォルダへ保存
‘ – ただし、元ファイルが未保存 または 保存先フォルダが存在しない場合:
‘ → サインイン中ユーザーの「ドキュメント」フォルダへ保存
‘ ※ Public ではなく、ユーザー固有の My Documents を使用

‘ 配置先:PERSONAL.XLSB(個人用マクロブック)推奨
‘ 実行時:コピー元となる 元ファイル をアクティブにしてから実行
‘=================================================
Public Sub Export_Set_テンプレート()

'==================== 設定(この3行だけ変更すればよい) ====================
Dim 出力名 As String: 出力名 = "コピー出力.xlsx"   '← 保存ファイル名(拡張子未指定なら自動で .xlsx 付与)
Dim コピーシート As String: コピーシート = "Sheet2,Sheet3,Sheet10,"  '← カンマ区切り。末尾カンマOK
Const 上書き禁止 As Boolean = False   '← Trueにすると、既存同名ファイルがある場合は日時付きで別名保存
'==========================================================================

'▼ ここから下は原則いじらない ------------------------------
Dim wbOrg As Workbook          ' 元ファイル(コピー元)
Dim wbNew As Workbook          ' 新規作成されるブック(コピー先)
Dim ws As Worksheet            ' シートループ用
Dim savePath As String         ' 保存先フルパス
Dim orgWbName As String        ' 元ファイル名(例:"Sample.xlsm")
Dim userDocs As String         ' 現ユーザーのドキュメントフォルダ
Dim rngF As Range              ' 数式セル範囲
Dim c As Range                 ' セルループ
Dim f As String                ' 数式文字列
Dim TARGET_SHEETS As Variant   ' コピー対象シート配列
Dim tmpArr As Variant          ' Split中間配列
Dim buf() As String            ' 空要素除去後の配列
Dim i As Long, n As Long       ' ループカウンタ等
Dim links As Variant           ' LinkSources結果
Dim tryPath As String          ' 保存時の一時パス

On Error GoTo ErrHandler       ' 予期せぬエラー捕捉

'▼ 元ファイル(アクティブブック)を取得
Set wbOrg = ActiveWorkbook

'▼ 元ファイル名を取得(参照式置換・値化判定に使用)
orgWbName = wbOrg.Name

'▼ 出力名に拡張子が無い場合は自動で .xlsx を付与
If InStr(1, 出力名, ".", vbTextCompare) = 0 Then
    出力名 = 出力名 & ".xlsx"
End If

'▼ 文字列 → 配列(Split)し、Trim & 空要素除去して TARGET_SHEETS を確定
tmpArr = Split(コピーシート, ",")      ' 一旦カンマで分割
n = -1
For i = LBound(tmpArr) To UBound(tmpArr)
    Dim s As String
    s = Trim$(CStr(tmpArr(i)))          ' 前後空白除去
    If Len(s) > 0 Then                  ' 空要素は捨てる(末尾カンマ等に耐性)
        n = n + 1
        If n = 0 Then
            ReDim buf(0 To 0)
        Else
            ReDim Preserve buf(0 To n)
        End If
        buf(n) = s
    End If
Next i
If n = -1 Then
    MsgBox "コピー対象シートが指定されていません(空です)。", vbExclamation
    Exit Sub
End If
TARGET_SHEETS = buf  ' 最終的なコピー対象リスト

'▼ 現ユーザーのドキュメントフォルダ(Publicではなく個人用)
userDocs = CreateObject("WScript.Shell").SpecialFolders("MyDocuments")

'▼ 保存先フォルダの存在に応じて保存パスを決定
If wbOrg.Path = "" Then
    savePath = userDocs & "\" & 出力名
Else
    savePath = wbOrg.Path & "\" & 出力名
    If Dir(wbOrg.Path, vbDirectory) = "" Then
        savePath = userDocs & "\" & 出力名
    End If
End If

'▼ 上書き禁止の場合、同名ファイルが既に存在していれば日時付きに変更
If 上書き禁止 Then
    If Dir(savePath, vbNormal) <> "" Then
        savePath = Left$(savePath, Len(savePath) - 5) & _
                   "_" & Format(Now, "yyyymmdd_HHMMSS") & ".xlsx"
    End If
End If

'▼ 実行最適化:画面更新停止 + 保存確認ダイアログ抑止
Application.ScreenUpdating = False
Application.DisplayAlerts = False

'▼ 指定シートのみを新規ブックとしてコピー(順序は配列の並びどおり)
wbOrg.Worksheets(TARGET_SHEETS).Copy
Set wbNew = ActiveWorkbook

'==================== 参照の整理(外部 → 内部 → 値化) ====================
For Each ws In wbNew.Worksheets

    '--- シート内の「数式セルのみ」を抽出(数式が無いとエラー→吸収)
    On Error Resume Next
    Set rngF = ws.UsedRange.SpecialCells(xlCellTypeFormulas)
    On Error GoTo 0

    '--- 数式セルが無ければ次のシートへ
    If rngF Is Nothing Then GoTo NextSheet

    '--- (1) 元ファイル参照のうち、コピー先同士の参照は内部参照へ置換して式を保持
    '    例:=[元ファイル.xlsm]Sheet3!A1 → =Sheet3!A1
    For i = LBound(TARGET_SHEETS) To UBound(TARGET_SHEETS)
        rngF.Replace _
            What:="[" & orgWbName & "]" & CStr(TARGET_SHEETS(i)) & "!", _
            Replacement:=CStr(TARGET_SHEETS(i)) & "!", _
            LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
    Next i

    '--- (2) 置換後の数式セルを再取得(式が更新されているため)
    On Error Resume Next
    Set rngF = ws.UsedRange.SpecialCells(xlCellTypeFormulas)
    On Error GoTo 0

    '--- (3) 依然として数式内に [元ファイル] が残るセル(= コピー外参照)は値確定
    If Not rngF Is Nothing Then
        For Each c In rngF.Cells
            f = CStr(c.Formula)
            If InStr(1, f, "[" & orgWbName & "]", vbTextCompare) > 0 Then
                c.Value = c.Value   '数式 → 値(入力規則・フィルタは維持)
            End If
        Next c
    End If

NextSheet:
Set rngF = Nothing
Next ws

'--- (4) セル外(定義名 / グラフ系列 / 検証のリスト参照 等)に残る元ファイル参照も BreakLink で除去
On Error Resume Next
links = wbNew.LinkSources(Type:=xlLinkTypeExcelLinks)
If Not IsEmpty(links) Then
    For i = LBound(links) To UBound(links)
        If InStr(1, CStr(links(i)), orgWbName, vbTextCompare) > 0 Then
            wbNew.BreakLink Name:=links(i), Type:=xlLinkTypeExcelLinks
        End If
    Next i
End If
On Error GoTo 0

'==================== 新規ブックを保存 ====================
tryPath = savePath
wbNew.SaveAs Filename:=tryPath, FileFormat:=xlOpenXMLWorkbook

CleanExit:
‘▼ 後片付け:表示系設定を元へ
Application.DisplayAlerts = True
Application.ScreenUpdating = True

'▼ 完了通知
MsgBox "新しいブックを保存しました:" & vbCrLf & tryPath, vbInformation
Exit Sub

ErrHandler:
‘▼ エラー時の後片付けと通知
Application.DisplayAlerts = True
Application.ScreenUpdating = True
MsgBox “エラー発生:” & Err.Description, vbExclamation

End Sub

コメント

タイトルとURLをコピーしました