excelで不要なStyleが増えてしまうので、削除するマクロを組みました。
そのときのメモ。
参考サイト:https://gist.github.com/YoshihitoAso/311b0a1d40174e1bfdae

参考サイトと違うところ:
1.複数のファイルを対象にStyleの削除を行う
 (Excelのシートから対象フォルダを選択→実行させたい)
2.Styleの削除を行ったファイル名と削除した件数を書き出す
3.名前定義の削除を選択したい

完成図

完成図はこんな感じ。

操作としては、
i) 「対象のディレクトリ選択」ボタンでディレクトリを選択
  →選択するとB6のセルに、選択したディレクトリパスが表示される

ii) C6セルで、選択した配下にある子ディレクトの下のファイルもすべて対象にするか選択
   TRUE:子ディレクトリ含むすべてのファイルを対象とする
  FALSE: 選択したディレクトリのファイルのみ対象とする

iii) 名前定義も含めて削除するか選択
   TRUE: 名前定義も削除する
  FALSE: 名前定義を削除対象にしない

iv) 「実行」ボタン
  →完了後、B10/C10/D10セル以降にそれぞれ、
   Bセル:対象としたファイルの名前
   Cセル:削除したスタイルの数
   Dセル:実行した日付
  を記入する。(ログとして活用)

実際に作成していく

プロジェクトの構成

実際にマクロを組んでいくのですが、プロジェクトの構成を先に。

上記1で「対象のディレクトリ選択」ボタンを作成しましたが、このボタンを右クリックして、
「マクロを登録」> 「新規作成」を押すと、上記の図のように、「標準モジュール」という
モジュールが作成され、コードを記述する画面がでてきます。
が、今回、ボタンの動作はここには書かないことにします。

上記のプロジェクトの構成図で行くと、下記のような感じでわけたいと思います。
(MVC的なことを考えれば、こんな構成が普通かなと思うので、、、なんとなくですがw)
※①~⑤の数字は、実装していく予定の順番です

-VBAPProject(remTest.xlsx)
|_MicroSoft Excel Objects
| |_Sheet1(Sheet1)
| |_「対象のディレクトリ選択」ボタンを押したときに呼ばれる関数②
| |_「実行!」ボタンを押したときに呼ばれる関数⑥
| |_Sheet2(Sheet2)
| |_Sheet3(Sheet3)
| |_ThisWorkbook
|
|_標準モジュール
|_Module1
|_ファイル選択ロジック(「ファイル選択」ボタンから呼ばれる①
|_名前定義削除ロジック(「実行!」ボタンの関数から呼ばれる③
|_標準以外のStyleの削除ロジック(「実行!」ボタンの関数から呼ばれる④
|_名前定義削除ロジックと標準以外のStyle削除ロジックを呼び出すメソッド(「実行!」から呼ばれる⑤
   (サブディレクトリを対象にする際、再帰的に呼び出す関数として使いたいので、ここにまとめる)

「対象のディレクトリ選択」ボタンの実装

 

ファイル選択ロジック作成

  ①のファイル選択ロジック:(Module1に記述)
  まずは、ファイルを選択されたときのロジックを作成します。


'フォルダを選択するダイアログを表示して、パスを取得する
'返り値:選択したディレクトリ名(String型)
Function fncSelectFolder() As String
    Dim returnString As String
    
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show Then
            returnString = .SelectedItems(1)
        End If
    End With
    
    fncSelectFolder = returnString
End Function

コメントに何をしているか書いておりますので、解説は省きますが、2点ほど補足。
・変数宣言は基本、関数の中に書いて、呼ばれたときに初期化させる
 (今回は、グローバル変数的に使うことはないので、基本、個々の関数の中で定義します)
・With~End Withは、(VBAを書いている人にはおなじみかもしれませんが)、
With句で呼び出したオブジェクトのプロパティや関数にアクセスする際、オブジェクト名を省略して
記述することができるステートメントです。(上記の場合、If .Showというところで、Application.FileDialogオブジェクトに
アクセスすることができています)なるほど、これはちょっといいね!w

ディレクトリ選択」ボタンを押下時の動きを紐づける

 ②の「対象のディレクトリ選択」ボタンを押したときの動き、上記2-2-1で作成した関数に紐づけます。

※Sheet1のファイルに記述


'ディレクトリ選択ボタン押下時
Sub btnSelectDirectory_Click()
    'エラーは無視
    On Error Resume Next

    '選択したファイルを保存するための変数
    Dim StrPath As String
    
    'ディレクトリの選択
    StrPath = Module1.fncSelectFolder()
    
    'Sheet1のB6セルに選択したディレクトリパスを記述
    If StrPath <> "" Then
        ThisWorkbook.Worksheets("Sheet1").Range("B6").Value = StrPath
    End If
End Sub

これで、「対象のディレクトリを選択」ボタンを押すと、ディレクトリ選択のダイアログが表示され、
ディレクトリを選択すると、Sheet1のB6に選択したディレクトリパスが記述されます。

「実行!」ボタンの実装

では、実際にスタイルを削除するロジックを実装します。

名前定義削除ロジック(「実行!」ボタンの関数から呼ばれる③

引数にファイルのフルパスを指定すれば、そのファイルを、指定しなければ現在アクティブなファイルを削除することとします。
(引数なしは、先にOpenなどで対象ファイルを開いていることを前提)
(Module1に記述)


'名前定義を削除する
'引数:削除するファイル名(フルパス)
'返り値:削除した件数(Long型)
Function funcDeleteNamesfunctions(Optional openFileName As String) As Long
    'エラーは無視
    On Error Resume Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName ="") Then
        '現在のワークブックの名前を覚えておく
        Dim baseFileName As String
        Dim baseFileSheetName As String
        baseFileName = ActiveWorkbook.FullName
        baseFileSheetName = ActiveWorkbook.ActiveSheet.Name
        
        'ファイルを開く
        Application.ScreenUpdating = False
        Application.DisplayAlerts = False
        Call Workbooks.Open(openFileName, ReadOnly:=False, Notify:=False)
    End If
    
    Dim nm As Name
    Dim nmCcnt As Long
    For Each nm In ActiveWorkbook.Names
        '実際に削除
        nm.Delete
        nmCnt = nmCnt + 1
    Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        'ファイルの保存
        ActiveWorkbook.Save
        ActiveWorkbook.Close
        
        '元のファイルをアクティブ化させる
        Workbooks(baseFileName).Sheets(baseFileSheetName).Active
    End If
    
    funcDeleteNamesfunctions = nmCnt
End Function

 

標準以外のStyleの削除ロジック(「実行!」ボタンの関数から呼ばれる④

こちらも引数にファイルのフルパスを指定すれば、そのファイルを、指定しなければ現在アクティブなファイルを削除することとします。
(引数なしは、先にOpenなどで対象ファイルを開いていることを前提)


'標準以外のスタイルを削除
'引数:削除するファイル名(フルパス:省略可)
'返り値:削除した件数
Function funcDeleteStyle(Optional openFileName As String) As Long
    On Error Resume Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        '現在のワークブックの名前を覚えておく
        Dim baseFileName As String
        Dim baseFileSheetName As String
        baseFileName = ActiveWorkbook.FullName
        baseFileSheetName = ActiveWorkbook.ActiveSheet.Name
        
        'ファイルを開く
        Application.ScreenUpdating = False
        Application.DisplayAlerts = False
        Call Workbooks.Open(openFileName, ReadOnly:=False, Notify:=False)
    End If
    
    Dim i As Long
    Dim cnt As Long
    Dim style As Object
    
    '対象のファイルに含まれるスタイルの数だけ繰り返す
    For i = ActiveWorkbook.Styles.Count To 1 Step -1
        'スタイルを取得
        Set style = ActiveWorkbook.Styles.Item(i)
        
        '標準以外のスタイルを削除する
        If InStr("Hyperlink,Normal,Followed Hyperlink", style.Name) = 0 Then
            style.Delete
            cnt = cnt + 1
        End If
    Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        'ファイルの保存
        ActiveWorkbook.Save
        ActiveWorkbook.Close
        
        '元のファイルをアクティブ化させる
        Workbooks(baseFileName).Sheets(baseFileSheetName).Active
    End If
    
    '削除した件数を返す
    funcDeleteStyle = cnt

End Function

名前定義削除ロジックと標準以外のStyle削除ロジックを呼び出すメソッド(「実行!」から呼ばれる⑤

   (サブディレクトリを対象にする際、再帰的に呼び出す関数として使いたいので、ここにまとめる)
(Sheet1に記述)


'実行
'引数:
' 対象のディレクトリパス(String型)
' 名前定義を削除するか(Boolean型)
' サブディレクトリを対象とするか(Boolean型)
'返り値:
' なし
Function funcDeleteSheetStyles(Path As String, NameDelFlg As Boolean, SubDirFlg As Boolean)
    On Error Resume Next
    
    Dim buf As String
    Dim tgFileName As String
    Dim tgDir As Object
    Dim n As Long 'ログ書き出し用(書き出す行数)
    Dim cnt As Long '標準スタイル削除した数
    Dim ncnt As Long '名前定義を削除した数
    Dim msg As String '最後に出力する用
    
    '現在のファイルをメモしておく
    Dim StrWorkSheetName As String
    Dim BaseBookSheet As Worksheet '実行するエクセルのワークブックを覚えておくため
    
    StrWorkSheetName = ActiveWorkbook.ActiveSheet.Name
    Set BaseBookSheet = ThisWorkbook.Worksheets(StrWorkSheetName)
    
    '最後の行取得
    n = Cells(Rows.Count, "B").End(xlUp).Row + 1
    
    '指定されたディレクトリのファイルを取得する
    buf = Dir(Path & "\*.*")
    
    'ディレクトリ内のファイルの数だけ繰り返す
    Do While buf <> ""
        '拡張子が「.xls」もしくは「.xlsx」のものだけ対象とする
        If InStr(buf, ".xls") > 0 Or InStr(buf, ".xlsx") > 0 Then
            '処理対象としたファイルを書き出す
            BaseBookSheet.Range("B" & n).Value = buf
            
            '対象ファイルを開きActive化する
            Application.ScreenUpdating = False
            Application.DisplayAlerts = False
            tgFileName = Path & "\" & buf
            
            '対象のファイルを開く
            Call Workbooks.Open(tgFileName, ReadOnly:=False, Notify:=False)
            
            '名前定義を削除
            If NameDelFlg Then
                '先に開いてアクティブ化させたので引数なし
                ncnt = funcDeleteNamesfunctions()
                msg = ncnt & "件の名前定義を削除" & vbNewLine
            End If
            
            '標準スタイル以外を削除(これも開いているので引数なし)
            cnt = funcDeleteStyle()
            
            'ファイルの保存
            Workbooks(buf).Save
            Workbooks(buf).Close
            
            '処理した件数の書き出し
            BaseBookSheet.Range("C" & n).Value = msg & cnt & "件のスタイル(標準以外)削除"
            BaseBookSheet.Range("D" & n).Value = Now
            
            n = n + 1
        End If
        buf = Dir()
    Loop
    
    'サブディレクトリも対象の時
    If SubDirFlg Then
       With CreateObject("Scripting.FileSystemObject")
            For Each tgDirectory In .GetFolder(Path).SubFolders
                Call funcDeleteSheetStyles(tgDirectory.Path, NameDelFlg, SubDirFlg) '再帰サブルーチン
            Next tgDirectory
        End With
    End If
    

End Function


実行!」ボタンを押したときに呼ばれる関数⑤

「実行!」ボタンが押されたときに呼ばれる関数を実装します。
(Sheet1に記述)


'「実行!」ボタン押下時
Sub btnExcec_click()
    Dim NameDelFlg As Boolean '名前定義も削除する?
    Dim SubDirFlg As Boolean 'サブディレクトリも対象とする?
    Dim StrPath As String '対象のディレクトリ名
    
    '現在のファイル
    Dim StrWorkSheetName As String
    Dim BaseBookSheet As Worksheet '実行するエクセルのワークブックを覚えておくため
    
    StrWorkSheetName = ActiveWorkbook.ActiveSheet.Name
    Set BaseBookSheet = ThisWorkbook.Worksheets(StrWorkSheetName)
    
    StrPath = BaseBookSheet.Range("B6").Value
    SubDirFlg = BaseBookSheet.Range("C6").Value
    NameDelFlg = BaseBookSheet.Range("D6").Value
    
    'パスが入力されていない場合処理終了
    If StrPath = "" Then
        MsgBox "処理に失敗しました"
        End
    End If
    
    '実行
    Call Module1.funcDeleteSheetStyles(StrPath, NameDelFlg, SubDirFlg)
    MsgBox "完了"
    

End Sub

最後に、ボタンに作成した関数を紐づけて終了

「ディレクトリを選択ボタン」
 「ディレクトリを選択」ボタンを右クリック > マクロを登録  > btnSelectDirectory_Click

「実行!」
 「実行!」ボタンを右クリック > マクロ登録 > btnExcec_click

上記で完成です。

最後に、上記で作成した2つのコードファイルをペタリしておきます。

[amazonjs asin=”4774173673″ locale=”JP” title=”Excel VBA 本格入門 ~日常業務の自動化からアプリケーション開発まで~”]

[amazonjs asin=”4798047341″ locale=”JP” title=”大村あつし の Excel VBA Win64/32 APIプログラミング”]

[amazonjs asin=”4990512405″ locale=”JP” title=”VBAエキスパート公式テキスト Excel VBA ベーシック 模擬問題プログラム付き”]

[amazonjs asin=”4062577690″ locale=”JP” title=”入門者のExcel VBA―初めての人にベストな学び方 (ブルーバックス)”]

全コード

sheet1(コード)


'ディレクトリ選択ボタン押下時
Sub btnSelectDirectory_Click()
    'エラーは無視
    On Error Resume Next

    '選択したファイルを保存するための変数
    Dim StrPath As String
    
    'ディレクトリの選択
    StrPath = Module1.fncSelectFolder()
    
    'Sheet1のB6セルに選択したディレクトリパスを記述
    If StrPath <> "" Then
        ThisWorkbook.Worksheets("Sheet1").Range("B6").Value = StrPath
    End If
End Sub


'「実行!」ボタン押下時
Sub btnExcec_click()
    Dim NameDelFlg As Boolean '名前定義も削除する?
    Dim SubDirFlg As Boolean 'サブディレクトリも対象とする?
    Dim StrPath As String '対象のディレクトリ名
    
    '現在のファイル
    Dim StrWorkSheetName As String
    Dim BaseBookSheet As Worksheet '実行するエクセルのワークブックを覚えておくため
    
    StrWorkSheetName = ActiveWorkbook.ActiveSheet.Name
    Set BaseBookSheet = ThisWorkbook.Worksheets(StrWorkSheetName)
    
    StrPath = BaseBookSheet.Range("B6").Value
    SubDirFlg = BaseBookSheet.Range("C6").Value
    NameDelFlg = BaseBookSheet.Range("D6").Value
    
    'パスが入力されていない場合処理終了
    If StrPath = "" Then
        MsgBox "処理に失敗しました"
        End
    End If
    
    '実行
    Call Module1.funcDeleteSheetStyles(StrPath, NameDelFlg, SubDirFlg)
    MsgBox "完了"

End Sub

Module1(コード)


'フォルダを選択するダイアログを表示して、パスを取得する
'返り値:選択したディレクトリ名(String型)
Function fncSelectFolder() As String
    Dim returnString As String
    
    With Application.FileDialog(msoFileDialogFolderPicker)
        If .Show Then
            returnString = .SelectedItems(1)
        End If
    End With
    
    fncSelectFolder = returnString
End Function


'名前定義を削除する
'引数:削除するファイル名(フルパス:省略可)
'返り値:削除した件数(Long型)
Function funcDeleteNamesfunctions(Optional openFileName As String) As Long
    'エラーは無視
    On Error Resume Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        '現在のワークブックの名前を覚えておく
        Dim baseFileName As String
        Dim baseFileSheetName As String
        baseFileName = ActiveWorkbook.FullName
        baseFileSheetName = ActiveWorkbook.ActiveSheet.Name
        
        'ファイルを開く
        Application.ScreenUpdating = False
        Application.DisplayAlerts = False
        Call Workbooks.Open(openFileName, ReadOnly:=False, Notify:=False)
    End If
    
    Dim nm As Name
    Dim nmCcnt As Long
    For Each nm In ActiveWorkbook.Names
        '実際に削除
        nm.Delete
        nmCnt = nmCnt + 1
    Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        'ファイルの保存
     Workbooks(buf).Save
        Workbooks(buf).Close
        
        '元のファイルをアクティブ化させる
        Workbooks(baseFileName).Sheets(baseFileSheetName).Active
    End If
    
    funcDeleteNamesfunctions = nmCnt
End Function


'標準以外のスタイルを削除
'引数:削除するファイル名(フルパス:省略可)
'返り値:削除した件数
Function funcDeleteStyle(Optional openFileName As String) As Long
    On Error Resume Next
    
    '引数が存在する場合
    If Not ( IsMissing(openFileName) Or openFileName="") Then
        '現在のワークブックの名前を覚えておく
        Dim baseFileName As String
        Dim baseFileSheetName As String
        baseFileName = ActiveWorkbook.FullName
        baseFileSheetName = ActiveWorkbook.ActiveSheet.Name
        
        'ファイルを開く
        Application.ScreenUpdating = False
        Application.DisplayAlerts = False
        Call Workbooks.Open(openFileName, ReadOnly:=False, Notify:=False)
    End If
    
    Dim i As Long
    Dim cnt As Long
    Dim style As Object
    
    '対象のファイルに含まれるスタイルの数だけ繰り返す
    For i = ActiveWorkbook.Styles.Count To 1 Step -1
        'スタイルを取得
        Set style = ActiveWorkbook.Styles.Item(i)
        
        '標準以外のスタイルを削除する
        If InStr("Hyperlink,Normal,Followed Hyperlink", style.Name) = 0 Then
            style.Delete
            cnt = cnt + 1
        End If
    Next
    
    '引数が存在する場合
    If Not (IsMissing(openFileName) Or openFileName="") Then
        'ファイルの保存
        Workbooks(buf).Save
            Workbooks(buf).Close
        
        '元のファイルをアクティブ化させる
        Workbooks(baseFileName).Sheets(baseFileSheetName).Active
    End If
    
    '削除した件数を返す
    funcDeleteStyle = cnt

End Function


'実行
'引数:
' 対象のディレクトリパス(String型)
' 名前定義を削除するか(Boolean型)
' サブディレクトリを対象とするか(Boolean型)
'返り値:
' なし
Function funcDeleteSheetStyles(Path As String, NameDelFlg As Boolean, SubDirFlg As Boolean)
    On Error Resume Next
    
    Dim buf As String
    Dim tgFileName As String
    Dim tgDir As Object
    Dim n As Long 'ログ書き出し用(書き出す行数)
    Dim cnt As Long '標準スタイル削除した数
    Dim ncnt As Long '名前定義を削除した数
    Dim msg As String '最後に出力する用
    
    '現在のファイルをメモしておく
    Dim StrWorkSheetName As String
    Dim BaseBookSheet As Worksheet '実行するエクセルのワークブックを覚えておくため
    
    StrWorkSheetName = ActiveWorkbook.ActiveSheet.Name
    Set BaseBookSheet = ThisWorkbook.Worksheets(StrWorkSheetName)
    
    '最後の行取得
    n = Cells(Rows.Count, "B").End(xlUp).Row + 1
    
    '指定されたディレクトリのファイルを取得する
    buf = Dir(Path & "\*.*")
    
    'ディレクトリ内のファイルの数だけ繰り返す
    Do While buf <> ""
        '拡張子が「.xls」もしくは「.xlsx」のものだけ対象とする
        If InStr(buf, ".xls") > 0 Or InStr(buf, ".xlsx") > 0 Then
            '処理対象としたファイルを書き出す
            BaseBookSheet.Range("B" & n).Value = buf
            
            '対象ファイルを開きActive化する
            Application.ScreenUpdating = False
            Application.DisplayAlerts = False
            tgFileName = Path & "\" & buf
            
            '対象のファイルを開く
            Call Workbooks.Open(tgFileName, ReadOnly:=False, Notify:=False)
            
            '名前定義を削除
            If NameDelFlg Then
                '先に開いてアクティブ化させたので引数なし
                ncnt = funcDeleteNamesfunctions()
                msg = ncnt & "件の名前定義を削除" & vbNewLine
            End If
            
            '標準スタイル以外を削除(これも開いているので引数なし)
            cnt = funcDeleteStyle()
            
            'ファイルの保存
            Workbooks(buf).Save
            Workbooks(buf).Close
            
            '処理した件数の書き出し
            BaseBookSheet.Range("C" & n).Value = msg & cnt & "件のスタイル(標準以外)削除"
            BaseBookSheet.Range("D" & n).Value = Now
            
            n = n + 1
        End If
        buf = Dir()
    Loop
    
    'サブディレクトリも対象の時
    If SubDirFlg Then
       With CreateObject("Scripting.FileSystemObject")
            For Each tgDirectory In .GetFolder(Path).SubFolders
                Call funcDeleteSheetStyles(tgDirectory.Path, NameDelFlg, SubDirFlg) '再帰サブルーチン
            Next tgDirectory
        End With
    End If
    

End Function


投稿者 iyken

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です