PLAIN-TEXT BASIC, RUN AGAINST DOCUMENTS THAT CANNOT STORE MACROS

マクロを置けない文書を、平文の Basic で動かす。 Office 無しで、文書を動かす。

Microsoft Office は要りません。文書の形式はそのままに、 中身だけを機械で処理します。ソースは平文なので差分が読めます。

道具もこのページも AI が書き、AI が描画して確かめました根拠は視覚 QA確認していないことに書いてあります。

Amount.bas 平文。git に置く
u = oSheet.getCellByPosition(2, i).getValue()
q = oSheet.getCellByPosition(3, i).getValue()
oSheet.getCellByPosition(4, i).setValue(u * q)
total = total + u * q
basrun apply
見積書.xlsx マクロは入らない
1,28040 51,200
340120 40,800
95500 47,500
8,6006 51,600
72080 57,600
合計 248,700
詰まる場所THE CONSTRAINT

たとえば、こういう場面です。

「この見積、金額と合計を入れて今日中にお願いします。
毎月同じ形で来るので、来月からも」

  • 渡されたのは .xlsxマクロは 1 バイトも入っていない
  • 手元の端末に Microsoft Office が無い
  • 相手の運用は変えられない。形式もそのまま返すのが前提
  • 同じ処理が来月もある。今回かぎりの手作業では終わらない

この依頼は、渡されたファイルが .xlsx だと素直には成立しません。 .xlsx は仕様としてマクロを格納できないからです(マクロは .xlsm 側)。 VBA を書けるかどうかではなく、書いたものの置き場所がないという形で詰まります。 そして逃げ道は 3 つとも、何かを諦めることになります。

形式を変える

.xlsm に変換する。相手の運用を変えることになり、受け入れられないことがある。

値を直接書く

計算結果だけ埋める。再実行できず、式も残らない。次に数字が変われば作り直し。

諦める

手作業に戻す。枚数や月数に比例して時間が増える。来月も同じだけかかる。

3 つとも、技術的な限界ではありません。 できない理由が仕様に書いてあるので、そこで止まりやすいだけです。 止まっているのは 格納 の側であって、実行 の側ではありません。

制約は格納側にあるSTORAGE, NOT EXECUTION

格納できないだけで、実行できないわけではありません。 ソースを実行時に Basic ライブラリへ流し込めば、文書は普通の .xlsx のまま処理できます。

平文のソース src/Amount.bas git diff が読める。真実はここ apply 流し込む Basic ライブラリ MyLib 実行時だけ。終わればもう無い 文書を処理 文書 book.xlsx ソースは埋め込まれない pull ― 文書に埋まってしまったマクロを、平文へ救出する
平文のソース src/Amount.bas git diff が読める。真実はここ apply 流し込む Basic ライブラリ MyLib 実行時だけ。終わればもう無い 文書を処理 文書 book.xlsx ソースは埋め込まれない pull ― 埋まったマクロを平文へ救出
# ソースは平文のまま。文書には一切埋め込まない
python basrun.py apply book.xlsx src MyLib Amount.FillAmounts --backup

# 文書に埋まってしまったマクロを、平文へ救出することもできる
python basrun.py pull rescued Standard --book legacy.ods

回り道した先のほうが、本来の形として優れています。

埋め込みマクロ
ソースの可読性

文書内の XML に埋まる

レビュー

実質できない

対象の形式

マクロを持てる形式のみ

真実の在処

文書

basrun
ソースの可読性

git diff が読める

レビュー

通常のコードレビュー

対象の形式

.xlsx .pptx .docx 共通

真実の在処

ソース(実行時のキャッシュ)

basrun が粗利率を埋めた月次表とグラフ

別の .xlsx ― 粗利率と % 書式は basrun が入れ、グラフと条件付き書式は生成時に。Excel は使っていない

作ったら、見るRENDER, THEN LOOK

文字列が正しいことと、読める状態であることは別です。 「うまくいきました」と表示するコードは、うまくいかなくてもそう表示します。 だから出来上がりを描画し、目で確かめてから完了とします。

値だけなら CSV に落とせば読めます。ですが CSV になった時点で、 結合・列幅・シートの構造は落ちます。座標そのものは数字として残っても、 見え方は残りません。グラフに至っては文字としての姿がないので、 書けているかどうかを読み返しで確かめる方法がありません。

文字として読める描画しないと分からない
セル値・数式・座標結合の見え方、列幅で切れた文字
書式指定した規則その規則が当たった結果の色
グラフ定義(XML)そもそも出ているかどうか

実際に踏みました。グラフの図形に 大きさが書かれておらず、グラフは存在するのに面積がゼロ ―― つまり 見えない状態になっていました。問い合わせれば「グラフ 1 個」と正しく返ります。 存在を確認する方法では、これは見つかりません。原因を 3 回続けて読み違え、 最後は「この描画系はグラフに対応していない」と道具の限界に帰着させました。 3 回とも外れです。描画して初めて、自分の生成物を疑えました。

basrun も、このページも、書いたのは AI です。
そして上の欠陥を見つけたのも、描画して見た AI 自身です。

  • AI は画像を読めます。ですが文書を画像にする経路が無ければ、 読む対象そのものがありません。ライブラリが返すのは値と書式の 指定であって、描画の結果ではないためです
  • そこで soffice で PDF にし、画像にしてから読み返す経路を作りました。 この節の 2 枚も、上の月次表も、そうやって一度見てから載せています
  • このページ自体も同じ手順で作りました。幅を変えて描画し、 見出しの折り返し・図の欠け・地と文字のコントラストを確かめています
basrun が版数を差し替えた作業指示書

.docx ― 版数の差し替えとロット件数の追記を basrun が実行

生成した 3-D 円グラフを描画したもの

.xlsx ― 3-D グラフとテクスチャ。描画しなければ確認できない領域

題が 2 行に折り返す

文字列としては完全に正しい。読み返しでは絶対に出ない欠陥。

暗い面に暗い文字

デザインシステムの色を名前で対応させ、載せる面の役割を落としていた。

下三分の一が空白

横幅で設計して縦の寸法を使っていなかった。数値上は正しい配置。

使い方GETTING STARTED

必要なのは LibreOffice だけです。Microsoft Office は要りません。 Python は LibreOffice に同梱のものを使います(素の Python には uno が無いためです)。

01

Sub を書く

ソースは平文の .bas。文書には一切埋め込まないので、そのまま git に置けます。

02

文書に当てる

実行時にライブラリへ流し込み、処理して保存します。形式は .xlsx のままです。

03

描画して見る

「うまくいきました」の表示ではなく、出来上がりを目で確かめてから完了とします。

' ★ 文書は引数で受ける。ThisComponent に頼らない
Sub FillAmounts(oDoc As Object)
    Dim oSheet As Object
    oSheet = oDoc.Sheets.getByIndex(0)
    ...
End Sub

ThisComponent は使えません。 --headless で非表示に開いた文書は「現在のコンポーネント」ではないためです。 成功したように見えて、何も起きません ― 実測で「読み込んだ / 実行した / 保存した」と全部表示され、セルは 1 つも変わっていませんでした。

# 同期して、当てて、保存する(--backup で元を残す)
python basrun.py apply book.xlsx src MyLib Amount.FillAmounts --backup

起動する LibreOffice は専用プロファイルで隔離します。 利用者が画面で開いている LibreOffice を巻き込まないためです。停止も taskkill ではなく、接続先だけを終了させます。 BASRUN_OFFICE / BASRUN_PROFILE / BASRUN_PORT で上書きできます。

確認していないことWHAT IS NOT VERIFIED

確かめた範囲と、確かめていない範囲を分けて書きます。 聞かれてから答えるのと、先に書いておくのとでは意味が違うためです。

確認していない

  • Windows でしか動かしていません。Linux / macOS のパス解決は書いてありますが未検証です。
  • 巨大な表(数万行規模の性能・メモリ)は試していません。結合セル・複数シートは確認しましたが、スケールは別問題です。
  • 描画に使うのは LibreOffice です。Excel / PowerPoint の描画とは異なります。 実測で、3-D 円グラフのラベル位置が両者で違いました。
  • 同梱している同期ツールは 2017 年公開で以降更新がありません。 現行の LibreOffice で動くことは確認済みですが、将来の互換性は保証できません。

確認した

  • 結合セル・複数シートで動くこと。既存の結合が処理の往復で保たれ、 2 枚目のシートを狙って書け、新しい結合も作れます ― 値だけでなく描画して見た目も確認しました。
  • テスト 22 件(単体 16 / 統合 6)。単独でも、通しでも 22/22 ― 通しで走らせて初めて出た欠陥が 1 件あり、直してあります。 LibreOffice が無い環境では統合分を飛ばします
  • 実行の前後で、利用者の既定プロファイルがバイト単位で不変であること
  • 処理後も vbaProject.bin を含まない、通常の .xlsx であること
  • 結果は生成に使った実装ではなく、別の実装で読み返して確認
  • このページも幅 1280 / 390 / 360 で描画して確認。地と本文のコントラストは 画素を読んで測定(最悪 8.2 : 1)、外部への通信は 0 件
借りているものBUILT ON
obasync 同期を委譲。imacat 作 / Apache-2.0 ― 無改変で同梱しています open-design 配色と立体。Apache-2.0 ― データだけ取り込み、常駐するものは入れていません

書き直す理由が無いものは書き直していません。組んで初めて出来ることのほうに時間を使っています。 ―― 文書を開いて中のマクロを平文へ救出する --book は、 どちらの道具にも単体では無かったものです。