[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『DIMの整理を効率的に進めたい』(すすむ)
VBAのコードを継ぎ足し継ぎ足しで書いているとDIMで宣言した名前を削除したり追加したりしていくので
宣言だけして最終的にどこでも使用していない名前が出てきました。
最終的に不要なモノを削除したいのですが何か効率的な方法はありますか?
昔々のBASICでは変数がどの行番地で使用されているか一覧でDAMPするようなソフトがありました。
VBAでもそのようなツールがあれば良いのでしょうが?
アドバイスできる事あればお願いします。
< 使用 Excel:Excel2021、使用 OS:Windows11 >
ぐぐって私が希望するような(参考になりそうな)情報がありました。
「マクロ整理ツールv1.01」を利用する事にしました。
気になったのは
「MZ-ToolsというツールのReviewSourceCodeで
未使用の変数を確認することができました。」
とあるのですが、
そもそもMz-Toolの使い方が良く理解できていないのが原因ですが
Mz-Toolsのどこにあるのか?
Mz-Tool(8.0)内を色々見ていますが探し切れていません。
ご存じの方は、教えてください。
(すすむ) 2023/12/18(月) 06:21:52
使ったことありませんが、検索すると 初心者備忘録 2015.10.5 新しくなったMZ-Tools https://www.ka-net.org/blog/?p=6260 がヒットしました。 下の方のアニメーションが、未使用変数の洗い出しをしているところみたいですね
Documentationを読むと https://www.mztools.com/v8/onlinehelp/MZTools8Help.html?review_quality.htm Dead Code Review というので、detect some unused declarations in the source code するようです (´・ω・`) 2023/12/18(月) 09:10:45
アクティブなブックにあるすべてのモジュールについて、 未使用変数を探して イミディエイトウインドウに出力するコードを書いてみました。
personal.xlsb に入れておき、main プロシージャーを クイックアクセスツールバーにでも登録するとよいかも知れません。
【仕様の概要】 ・モジュールベース変数とプロシージャベースの変数が対象です。 ・Public変数や、定数は除外しました(負荷の割に重要性は低いと思います。) ・クラスモジュールについては確認していません。
ユーザーインターフェイスは拙劣ですが、 コードがあるので、使用者がご自由に改変してください。
Microsoft Visual Basic for Applications Extensibility x.x の参照設定が必要です。
==以下、参考コード ============ Rem Microsoft Visual Basic for Applications Extensibility x.x の参照設定が必要です。
Option Explicit Type proc name As String code As String vars As String missing As String End Type
Dim re As Object
Sub main() Dim k As Long
'正規表現の用意 Set re = CreateObject("VBScript.RegExp") re.Global = True re.MultiLine = True
'ActiveWorkbookの各コンポーネントごとに処理 With ActiveWorkbook.VBProject For k = 1 To .VBComponents.Count Call checkUnusedVariables(.VBComponents(k).name) Next End With End Sub
'componentNameにある変数のうち、未使用のものをチェック Sub checkUnusedVariables(componentName As String)
Dim cMod As CodeModule Dim procs() As proc Dim pr As Variant
Dim p As Long Dim dic As Object Dim k As Long Dim buf As String
'対象となるモジュールの指定 Set cMod = ActiveWorkbook.VBProject.VBComponents(componentName).CodeModule
'(1)プロシージャレベル変数の未使用変数 -----------------------------------------
'プロシージャ名の取得 Set dic = CreateObject("Scripting.Dictionary") With cMod For k = 1 To .CountOfLines If buf <> .ProcOfLine(k, 0) Then buf = .ProcOfLine(k, 0) dic(buf) = Empty End If Next End With
p = -1 For Each pr In dic p = p + 1 ReDim Preserve procs(p) As proc procs(p).name = pr 'プロシージャ名 procs(p).code = cMod.Lines(cMod.ProcStartLine(pr, 0), _ cMod.ProcCountLines(pr, 0)) 'コード procs(p).code = commentOut(procs(p).code) 'コメントを削除した変数を保持 procs(p).vars = getVariables(procs(p).code) '■変数名(カンマで連結) procs(p).missing = getMissings(procs(p).vars, procs(p).code)'■未使用の変数名(同上)
If procs(p).missing <> "" Then Debug.Print componentName & " の "; procs(p).name & " の未使用変数は " & procs(p).missing End If Next
'(2)モジュールベース変数のうち未使用変数 --------------------------------------------- Dim declarationLines As Long Dim missing As String Dim code As String Dim vars As String
declarationLines = cMod.CountOfDeclarationLines If declarationLines > 1 Then code = cMod.Lines(1, declarationLines) '宣言セクションのコード code = commentOut(code) vars = getVariables(code) 'そこにある変数名たち
Dim var As Variant Dim flag As Boolean For Each var In Split(vars, ",") flag = False For k = 0 To UBound(procs) If InStr("," & procs(k).vars & ",", "," & var & ",") = 0 Then 'プロシージャレベルの変数ではなく If existsInCode(var, procs(k).code) Then flag = True Exit For End If End If Next If flag = False Then missing = missing & "," & var End If Next If missing <> "" Then Debug.Print componentName & " のモジュールレベル変数の未使用変数は " & Mid(missing, 2) End If End If End Sub
'コード内の(1)文字列部分および(2)コメントを消去した文字列を返す Function commentOut(code As String) As String re.Pattern = """.*?""" code = re.Replace(code, "")
re.Pattern = "('|Rem).*?$" commentOut = re.Replace(code, "") End Function
'コードsから宣言された変数名を取り出す(Public,Constは除外。重要性低いと見做す) Function getVariables(s As String) As String Dim ary, e, ary2, e2 Dim ans As String
ary = Split(s, vbCrLf) For Each e In ary If InStr(e, "Dim") > 0 And InStr(e, "Dim""") = 0 Then '文字列としてのDimは除外 ' Redim a(m, n) のような場合はカッコ部分を消去 re.Pattern = "\(.*?\)" re.Global = True e = re.Replace(e, "")
e = Replace(e, "ReDim Preserve", "") e = Replace(e, "ReDim", "") e = Replace(e, "Dim", "")
'複数の変数を一行内に記述した場合 If InStr(e, ",") > 0 Then ary2 = Split(e, ",") For Each e2 In ary2 ans = ans & "," & Split(Trim(e2), " ")(0) Next Else ans = ans & "," & Split(Trim(e), " ")(0) End If End If Next
For Each e In Split("$,&,#,!", ",") '型宣言文字への対応 ans = Replace(ans, e, "") Next getVariables = Mid(ans, 2) End Function
' 変数たちvarsのうち、codeで使われていない変数を返す Function getMissings(vars$, code$) As String Dim var As Variant Dim missing As String
For Each var In Split(vars, ",") If existsInCode(var, code) = False Then missing = missing & "," & var Next getMissings = Mid(missing, 2) End Function
'code の中に、(変数宣言以外で)変数varが使われていれば True、そうでなければ Falseを返す。 Function existsInCode(var As Variant, code As String) As Boolean Dim matches As Object, m As Object
'''re.Pattern = "^.*\b" & var & "\b" & ".*$" re.Pattern = "^.*[ (\r]" & var & "[ (),\r]" & ".*$" '''こちらに修正 Set matches = re.Execute(code) For Each m In matches If InStr(m.Value, "Dim") = 0 Then '宣言ではなく実際に使用された場合 existsInCode = True Exit For End If Next End Function
【補足】 「VBAでVBEを操作する」 http://officetanaka.net/excel/vba/vbe/ が参考になります。 余り念入りに検証していないので、想定外のことが起こり得ます。 ただし、元のコードには一切変更を加えていませんので、その点は安心ください。
なんだか、ゴテゴテしたコードになってしまったようです。 私なんか、未使用の変数があっても、それがどうした、という感じで余り気にしませんね。
"VBAでVBEを操作"の練習に取り組んでみました。 ちなみに、仕様追加とかは皆さんでお願いします。予定はありません。
# 昔、こういった類のコードを提示して、ウイルスに悪用されるとお叱りをいただいたことがあります。 (2023/12/19 コードを一部修正しました) (xyz) 2023/12/18(月) 10:21:00
チェックしてみましたが、以下のように但し書きがありました。
「VB/VBA では、private 宣言のみがレビューされます(パフォーマンス上の理由)」
C# and VB.NETでの使用を前提にしているようで
VBAでは、狭い範囲に限定されているようです。
(xyz)さん、Toolの作成ありがとうございます。
早速、利用させていただきます。
ド素人なので提示いただいたコードをどうにかして悪用するような知識は皆無なので安心してください。
(すすむ) 2023/12/18(月) 11:01:37
その後いくつか気づいたことをメモします。こういうことがまだまだあるかもしれません。
1. やはり文字列は消去しないといけないですね。 a = "変数名" などのコードがあると、その変数名を使用したことになってしまいます。 また、b = "'" & a などのコードがあると、 いまの処理では '以下が強制的にコメントと見なされて消されてしまいます。 (勿論、既存のコードは一切変わりませんが) コメントを消去する前に、まずは文字列を消去すれば、こうしたことは起きません。
2. モジュールレベル変数と同一名のプロシージャレベル変数がある場合(*)、 今のロジックだと、モジュールレベル変数の使用如何に拘わらず、 自動的にモジュールレベル変数が使用されていると見做されています。 これも理屈から言ったら対応が必要なんでしょう。 (*)そもそもこういう使い方はしないほうがいいかも。
追って、前に提示したコードを直接、変更してしまおうと思っています。 (12/19変更しました) (xyz) 2023/12/18(月) 23:26:09
xlsmファイルを起動しておしえてもらったコードをpersonal.xlsb(標準モジュール) にコピペ後
プロシージャーをクイックアクセスツールバーに登録しました。
Macro1のアイコンをクリックしましたが以下のエラーが出ます。
(そもそも利用の仕方がも違っている可能性もありますが。。。。)
マクロ’PERSONAL.XLSB!Module3.mainPERSONAL.XLSB!Module3.main’を実行できません。
このブックでマクロが使用できないか、または全てのマクロが無効になっている可能性があります。
以下の2点は修正済みですが他にチェックすべき点ありますか ?
1)トランスセンター > マクロの設定 では
「VBAマクロを有効にする」 にチェック済み
「VBAマクロが有効な場合にExcel4.0のマクロを有効にする」もチェック済み
2)トランスセンター >メッセージバーでは、
「ActivX コントロールやマクロなどのアクティブ コンテンツがブロックされた場合、すべてのアプリケーションにメッセージバーを表示する」もチェック済み
(すすむ) 2023/12/19(火) 09:15:52
紹介しましたサイトの http://officetanaka.net/excel/vba/vbe/01.htm にある設定を確認してください。 また、参照設定も必要です。 (Microsoft Visual Basic for Applications Extensibility x.x の参照設定)
なお、コードの修正は終了しています。掲載コードを書き替えました。
(xyz) 2023/12/19(火) 11:20:14
セキュリティ関係では既に触れた程度の話しかないと思います。 それでも引き続き同様の状態だとすると、失礼ながら、次のようなことを 疑わざるを得ません。
Personal.xlsbのModule3に mainというプロシージャが二つありませんか? ためしにこちらで実験すると、 「このブックでマクロが使用できないか、または全てのマクロが無効になっている可能性があります。」 と、まさにそちらと同様のエラーメッセージが表示されました。 まさかと思いますが、念のため確認してください。
Type proc .. End Type とか、 Dim re As Object とかのモジュールレベル変数、Typeを使っているので、 新しいModule(Module4とか)を作成して、そこにコピーするほうが間違いがないでしょう。 また、プロシージャ名もバッティングしにくく、名は体をあらわす"未使用変数抽出"などとすると よいかも知れません。 (xyz) 2023/12/21(木) 06:51:44
宣言したままで使用されていない変数(Public変数は除外します)の一覧を表示するツールです。
日本語変数名を使用したときに正常に機能していませんでした。(私は余り使わない) わかっていて放置するのも寝覚めが悪いので、修正しておきます。
【判明したバグ】 VBScriptの正規表現における"単語境界"(\b)は日本語と相性が悪い。 つまり、日本語変数名のあとの半角スペース(の直前)が単語境界と認識されません。 そこで単語境界(\b)の使用をやめました。過去発言のコードを直接変更しております。
(xyz) 2024/01/10(水) 23:40:16
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.