はじめに
excel vbaをやっている。IDEから文法から色々古く不便な部分も多いのだけれど、excelは四半世紀たっても未だに使われているアプリケーションだ。使われているとはいえ、エンジニアにとっては、excelは触りたくない対象だと思う。データの加工やgraph化であればpythonで事足りると。
それは一方では正しいと思うのだけど、Embededな環境でツールを使い作業してきた身としては、不便だったら便利にできないものか、というのと、自動化して便利にする手段は非エンジニアにとっては思いつくのが難しい、ということで、じゃあプログラミング一通りできる人がexcel vbaを再入門したらどのように環境を整えるのか、ということをやってみた。
環境
やったこと
やってないこと
まだまだ不足はあるけど、バージョン管理がストレスなくできれば半分片付いたようなものなので。その他はもうちょっとexcel vbaに習熟してからかな〜
バージョン管理の手順
成果物は
- https://github.com/knknkn1162/vba_extractor (docker image作成レポジトリ)
- https://github.com/knknkn1162/excel_vba_playground ( vba file群のレポジトリ)
でgit clone https://github.com/knknkn1162/excel_vba_playground
してmake
することで変更点のあるものだけをcommit, レポジトリにpushできるようにした。なので、
でvbaソースコードのバージョン管理ができるようになった。1番は相変わらずexcel付属のIDEを使用する点で不便だが、2番で快適になった。もう少しやったことを詳しく書くと、
- https://github.com/knknkn1162/vba_extractorレポジトリにdockerfileを配置し、circleCIによって、docker imageを自動的にdockerhubにプッシュされるようにした
- 1で作成したimageを用いて、.xlsmからexcel vbaコードを抽出できるようにした。ただし、コマンドがやや長いので、makefileを作成して抽出 -> git commit, pushをワンコマンドでできるようにした。ちなみに、複数のxlsmファイルにも対応した。
以下、作業過程の詳細。
vbaコードの抽出
xlsmはバイナリファイルなので、流石にそのままgithubのレポジトリに置くことはできない。excel vbaのソースコードは.xlsmファイルの内部で圧縮された状態1なので、コードの部分を取り出す必要がある。調べてみると、olevbaというのがあるので、これを用いる。ただし、そのまま使用するとソースコードのうち、日本語部分が文字化けすることがわかった。普通のプログラミング言語だと、日本語の対処は本質的でないことが多いので、後回しで考えることが多いが、excelの場合、通常セルやシート名に日本語が入っている場合が多いので、ソースコードにも日本語が含まれている場合が非常に多い(e.g. Worksheets("サンプル")
など)。そういうわけで早めに対応したほうがよさそうと判断しolevba.pyを読む2。
調査の結果、excel vbaを.xlsmファイルから抽出するときに、cp1252でエンコードしていることがわかった。vbaソースコードの文字コードは'shift_jis'となっているようなので、これが文字化けの原因のようだ。Pythonではmodule内の関数はモンキーパッチできない(よね? クラス内のメソッドはできるけど)ので、結局forkして以下のように修正することで対応した。VBA_Parser
クラスのextract_macros
メソッドを用いることと、抽出したコードで出てくるAttributeはいらないのでfilter_vba関数で取り除くことに注意してpythonスクリプトを書けばいい。
これを含む環境をdocker imageとして作成したのがhttps://github.com/knknkn1162/excel_vba_playground となる。内部ではcircleCIで都度docker imageを作成しdockerhubにpushしているので、docker push knknkn1162/vba_extractor
として、docker runコマンドを叩けば、vbaのファイルが作成されるようにした。ついでにcircleCIで日本語を含むxlsmファイルに対して、文字化けせずにソースコードを抽出できるかどうかのテストも書いた -> https://github.com/knknkn1162/vba_extractor/blob/0b927782052b90c9143105d6f96cc612f1934c6a/.circleci/config.yml#L33-L39。
.vbaコードのバージョン管理
上記で与えられたxlsmに対して、.vbaのコードを抽出することができた。ただ、docker run -it -v $(pwd):/code --rm knknkn1162/vba_extractor -- /code/hoge.xlsm
を毎回打つのは長いし、excelのIDEでコードが書き終わった状態なので、都度git add -p
-> git commit
-> git push
と分かりきったコマンドを打つのも面倒くさい。ということでMakefileを作成してmake
コマンドをうちさえすれば、諸々修正分がレポジトリにpushされるようにしてみた。一応工夫した所は以下の点:
- 複数のxlsmファイルの修正に対しても
make
コマンドの1コマンドで済むようにする - 作業中のexcelファイルには
~$sample.xlsm
みたいな感じのファイルが生成されるようなので、その対策 - xlsmファイルが複数のdirectoryにまたがっている場合でも
make
コマンドの1コマンドで済むようにする
ディレクトリ階層は変わるかもしれないがおおよそ次の通り:
. ├── Makefile <= 2. 1が済んだら`make` ├── README.md ├── excelvba1 <= 3. 2の実行でコードが抽出される(Module1.basがそれ) -> レポジトリにpush │ ├── ex001 │ │ ├── Module1.bas │ │ ├── Sheet1.bas │ │ └── ThisWorkbook.bas │ └── ex001.xlsm<= 1. vbaコードを編集 └── excelvba9 ├── ex001 │ ├── Module1.bas │ ├── Sheet1.bas │ └── ThisWorkbook.bas ├── ex001.xlsm ├── ex002 │ ├── Module1.bas │ ├── Sheet1.bas │ └── ThisWorkbook.bas └── ex002.xlsm <= 1. vbaコードを編集
vbaのコードを書いてみる
https://github.com/knknkn1162/excel_vba_playground では https://excel-ubara.com/ で出題されている練習問題をいくつか解いている。まだ単純だが、もうちょっと複雑なデモでも書ければ良いかな、と思っている。
次にできそうなこと
これはvbaファイルをvimなどで編集し、実行するときはexec_xlsm oo.vba --target xx.xlsm
みたいなコマンド叩くことでexcelが立ち上がってoo.vba
で指定したvbaマクロが実行するようにできそうな感じがする。もちろん、xx.xlsmにはなんらかのデータがsheetに入っている前提。ただし、vbaをxlsmにエキスポートする手段があんまりない(Pythonのxlwings
が有力?) もしかしたら文字化けなどでハマるかもしれない。
あとはweb上の連携だけど、これはGASのほうがふさわしいかな。
参考
-
olevbaのソースの該当箇所は https://github.com/decalage2/oletools/blob/v0.60/oletools/olevba.py#L3571-L3583。ちなみにolevba v0.60を使用した。2021.12.30現在pip installで取得できるバージョンに合わせた。↩
-
原因はhttps://medium.com/@saso_33429/excel%E3%83%9E%E3%82%AF%E3%83%AD%E3%81%AEvba%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92azure-devops%E3%81%A7%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95-d20b751ddc30 あたりも参考にしてみたがダメそうだった↩