ExcelでOfficeスクリプトを書くぞ! まずはHelloWorldだ!!
いつ手を出そうか機会を伺っていたのですが、デスクトップ版のExcelにも「自動化」タブがついてだいぶ浸透してきた気がするので、私もさわってみようかなって。新しい環境でのHelloWorldは楽しいですね!
利用条件
2024年6月の情報ですが、現状ではOfficeスクリプトは、すべてのExcelアプリで利用できるわけではありません。目安としては、Excelのリボンに「自動化」タブがあるか、ネット環境がありOneDriveに接続されているか、の2点がクリアされていれば利用できると思います。
買い切り版ではなくサブスク版のMicrosoft365であることが前提なのですが、ビジネス及び教育用ライセンスでは利用可能で、個人及び家族向けのライセンスでは利用不可能のようです。(現時点ではプレビュー段階であると書かれているので、実装予定はあるのかもしれません。)まず自分の環境で使えるかどうかを確認しないといけないですね。
Officeスクリプトとは
はじめにどんな言語かを知っておきたいと思って調べましたが、ベースになっているのはJavaScriptだそうで。私もPCに出会って長い人間ですので、馴染みのある言語です。たぶん中学生のときに初めて作ったホームページ(敢えて懐かしい表記をしますが)で、ウェブリングなんかを設置したくて見様見真似で書いたのが最古の記憶です(そのときはそれがJavaScriptという言語だということすらわかってなかった)。大学でやったのもこの言語だった気がするな~。このブログでもちょこっと使っています。
そのJavaScriptをベースに上位互換としてMicrosoftによって開発された言語がTypeScriptで、大きな違いは、型定義ができる(超ざっくり)とか、大規模開発にも向いているのだとか。
参考
で、そのTypeScriptをベースにMicrosoftOfficeで使える言語として登場したのがOfficeScriptsと呼ばれている、ということみたいですね。
VisualBasicをOffice用に適用したのがVisualBasic for Applications(VBA)で、同じようにTypeScriptをOffice用に適用したのがOfficeScriptsという認識でいいじゃんないですかね。
動かしてみる
2024年6月現在の「Microsoft 365 Business Standard」ライセンスによるデスクトップ版Excelのキャプチャです。まず「自動化」タブを開きます。サンプルのスクリプトがありますが、「新しいスクリプト」から自作してみましょう。
画面右側に「コードエディター」が現れます。「スクリプトを書く」をクリック。
こんな画面になりました。すでにサンプルのコードが書かれている状態で作成されるんですね。
このままでは読みにくいので、エディターを広げます。2行目のfunction main(略) {
と、12行目の}
が、プログロムの「枠」にあたる部分です。この中に書かれている命令で、Excelを動かします。
自分で書いたコードじゃないと実感が湧かないので、中身をいったん消しちゃって、以下の1文だけにしちゃいます。かっこの中の値を出力するコードです。TypeScriptでは、命令の終わりにセミコロンを付けます。
function main(workbook: ExcelScript.Workbook) { console.log("Hello World!"); }
スクリプトを実行するには、「実行」ボタンをクリックします。コードエディターの下へ、コードに書いた文字列が出力されました。やった!
とにもかくにも、Office付属の言語は環境構築をしなくても動く、っていうのがプログラミング初学者には最強に良いですよね。なにもしてないうちにつまづくとつらいですからね。
保存ボタンはここを押します。こまめに保存しましょう。Ctrl+Sでも保存できます。
このスクリプトの名前は、ここで変えることができます。デフォルトではOneDriveのドキュメント→Office Scriptsの中に保存されます。VBAのようにファイルに内包しないので、Excelファイルは.xlsxのままです。アクティブなExcelブックに対して、OneDriveに保存したスクリプトを実行する形式です。
変数宣言と代入
では、もうちょっと具体的なコードを書いていきましょう。最初にすべきことは、シート用のオブジェクト変数を作って、そこへ利用するシートを代入することなんじゃないかなと個人的には思います。これは、はじめに書かれていたコードの中にありました。変数名を、ワークシートを表す「ws」として書くと、こうなります。
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); }
「let ws」は「wsという変数を宣言します」の意味で、そこへ「= workbook.getActiveWorksheet()」と続けることで、「変数wsにこのワークブックのアクティブシートを代入します」と言っています。イコールは、「等しい」ではなく「代入」で、右の値を左に入れるイメージです。この1行で変数宣言と代入をいちどに行っているわけですね。
新しく勉強する言語なので、もう少し突っ込んで見ていこうと思います。TypeScriptでは変数宣言に使うのは「var」「let」「const」の3種類あるとのこと。
変数の中身を変えて使いたい場合は「let」、定数の場合は「const」で良さそうです。「let」で宣言した変数はそのブロック内でしか使えないことに注意が必要です。繰り返しや条件分岐ブロックの中で宣言した場合は、その中でしか有効にならないんですね。スコープ(有効範囲)は狭いほうがバグが起こりにくいですからね。
型定義
冒頭でもちょこっと書きましたが、TypeScriptはJavaScriptをベースに、型定義ができるようになった言語なんだそうです。プログラムの実行はfunction main()
から開始されますが、かっこの中に「workbook: ExcelScript.Workbook」と書いてありますよね。workbookという変数をExcelスクリプトのワークブック型として、型定義しています。で、スタート時にこの変数workbookにアクティブなワークブックが引数として代入されて、実行されるようです。
だから、変数workbook(アクティブワークブックが代入済)に対して、「アクティブワークシートを取得する」という命令である「.getActiveWorksheet()」が使えるんですね。
さて、「ExcelScript.Workbook」型があるなら、「ExcelScript.Worksheet」型だってあるはずですよね。さっき書いたコードで宣言した変数「ws」は型定義をしていませんが、TypeScriptの機能である型推論によって、自動でワークシート型にしてくれているんです。
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); //型推論によって型が定義される }
変数宣言・値代入と一緒に型定義も明確に行う場合は、以下のように「let 変数名: 型名 = 代入する値」と書きます。
function main(workbook: ExcelScript.Workbook) { let ws: ExcelScript.Worksheet = workbook.getActiveWorksheet(); //明確な型定義 }
おもしろかったのが、型定義の際、大文字から始まるものがオブジェクト型で、小文字から始まるものがプリミティブ型なんだそうです。へぇ~!
オブジェクト型とは、ここではざっくり「機能をたくさん持っている型」と表現しておきますね。プリミティブ型はその反対で「機能を持っていないシンプルな型」といったニュアンスです。
VBAで言うと、「Dim i As Long」と整数型で宣言した変数には「i = 1」と代入しますが、「Dim ws As Worksheet」とワークシート型で宣言したら「Set ws = Worksheets(“Sheet1”)」と代入の際にSetが必要になります。Setがあるものがオブジェクト型、ないものがプリミティブ型です。オブジェクト型変数は「ws.Name」のようにそのオブジェクトの機能が使えますが、プリミティブ型はそういった使い方ができません。
コードエディターで型定義を記述してみると、オブジェクト型(大文字)は緑っぽくてプリミティブ型(小文字)は青っぽいんですね。Date型はオブジェクト型なんだ!
型推論の機能は優秀で、サンプルスクリプトも型の定義は省略して書いてあるので、すべての型定義を明記する必要は無いように思えますが(そもそもExcel上で使うOfficeScriptsは、型を定義して書くほど大規模&複雑なものを作る想定ではないのでしょう)、知らないで書くより、型定義の方法も知ったうえで省略して書くぞ、という心持ちのほうが理解が深まるかなぁと思います。
セルに任意の値を入出力する
せっかくExcelにはシートとセルという強強UIが備わっているので、コンソールじゃなくてセルにHelloWorldを出してみましょう。
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); //アクティブシートを取得 ws.getRange("A1").setValue("Hello World!"); //A1セルへ値を入力 }
実行すると、A1セルにテキストが入りました。いいですね!
セル位置を数値で指定する場合は「getCell(行, 列)」で書きます。0から始まるので注意。
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); //アクティブシートを取得 ws.getCell(0, 0).setValue("Hello World!"); //A1セルへ値を入力 }
セルの値を取得するのは、こんな感じ
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); //アクティブシートを取得 console.log(ws.getRange("A1").getValue()); //A1セルの値をコンソールへ出力 //console.log(ws.getCell(0, 0).getValue()); //セル位置を数値で指定する場合はこっち }
繰り返し&条件分岐を使う
基本構文を使ったサンプルを書いてみました。図のようにA列に任意の数字があるとして、上から下まで繰り返して5以下だったら文字色を赤くします。
コードはこんな感じ。
function main(workbook: ExcelScript.Workbook) { let ws = workbook.getActiveWorksheet(); //アクティブシートを取得 let lastRow = ws.getUsedRange().getLastRow().getRowIndex(); //データ範囲の最終行取得 for (let row = 0; row <= lastRow; row++) { //変数rowを0から最終行まで繰り返し let tgtRange = ws.getCell(row, 0); //A列row行のセルを取得 if (tgtRange.getValue() <= 5) { //値が5以下だったら tgtRange.getFormat().getFont().setColor("red"); //文字色を赤くする } //if文の終わり } //for文の終わり }
実行すると、色が変わります。
コードエディターで「getValue」のところに黄色い波線が出ているのは、「繰り返しブロックの中で毎回セルの値を参照すると遅くなる可能性があるよ!」と注意してくれています。このくらいなら全然困りませんが、もっと数が多い場合はいったん配列に格納してそっちをループさせたほうが良さそうですね。
所感
もうちょっといろいろ作って記事も書きたいと思っていますが、感じたことなどを。
さわってみた感じ
手軽でいいですね!
コード画面と実行結果が同時に見えるのはわかりやすい! VBAだって画面を工夫すれば(大きさを半分ずつに調整して横に並べるとか)できるんだろうけど、デフォルトでこの形なのは良いなって。プログラム初学者さんがExcel作業の自動化やってみたい!って最初にさわるには、わかりやすいと思います。
ただデバッグ機能がもうちょっとあるといいな。どこでエラーが発生したかとかは教えてくれるけど、ブレイクポイントとか、1行ずつ実行する機能があったらありがたいんだけどな。いつか実装されるといいな~。
あと、以下のあたりも事前に知っておきたいですね。(2024年6月時点の仕様ですので、今後変わっていく可能性もあります。)
- 操作できるのは1つのアクティブワークブックのみ
- ほかのアプリケーションとの連携はできない
- メッセージボックス、ユーザーフォームなどのダイアログ系は利用できない
個人的には「この縛りで果たして……」って思ってたら、意外といけるじゃん! という感想です。現場のExcelに求められてるのって、こまごましたものが多いし、1つのアクティブブックの中で完結できるだけでも、実は十分な場合も多いんですよね。(あくまで私のいる環境で、ですが。)フォームが使えなくても、現場で入力してもらいたいパラメーターがあるなら、それ用のシートを用意するっていう方法もアリかなって思うし。工夫次第でいろいろ作れそうだなって。
自動化の選択肢が増えた
Officeスクリプトが使える環境だったらけっこう良いな、という感触なのですが、現状では、すべてのExcelで利用できるものではない、ということがまずは注意すべきポイントかなと。
私は組織で利用するアカウントも持っていますが、個人で仕事を請けることになったときにMicrosoft 365 Personal(当時はOffice 365 soloという名前だった)を契約して、けっこう長く利用しています。個人の仕事ではこちらのアカウントを使っているのですが、個人向けライセンスには、まだ自動化タブが現れないんです……! プレビュー段階とは言われているので、いつかはこっちでも使えるようになるのかな……?
法人向けの「Microsoft 365 Apps for business」あたりは1ユーザーならPersonalとそんなに値段も変わらないのでそっちに乗り換えるのも1つの手かなとも検討はしているのですが、個人事業として起業しているわけではないので、ちょっと悩みますね…。というか個人事業の方でもPersonalプラン使ってる人は多いんじゃないかなぁ。
ですのでOfficeスクリプトは、使える環境であることが前提になっちゃいますね。そのうえで、1つだけのブックだけで賄えるものならOfficeスクリプトでも良いと思うし、それ以上の規模を作りたいとなったら、そこから次の方法を検討すればいいんじゃないかなと。
Power Automate Desktopと組み合わせてもいいし、環境が許すならPythonで操作してもいいし。Excelだけで完結させたいならまだまだVBAの需要も高そうな気がします。どのバージョンのExcelでも、ネット環境の有無関係なくても、確実に動くというのはやっぱり強いですし。
結局は、どの方法にもメリット/デメリットがあるので、誰が/どんな環境で/どう使うか、ということをよく検討して、最適な方法を選択すればいいのだと思います。
コードは小規模なものを推奨されてる?
今回、Officeスクリプトについていろいろ調べながらコードを書いて、上に挙げた制限などを考えると、「Excelはあくまで、表計算ソフト。スクリプトはそんなに大きなものを作るためのものじゃなくて、ちょっとした機能にとどめておいてね」と言われている気がしました。
たしかに、昔から広く使われてきたExcelのVBAって「表計算ソフト」を超えてなんでもできすぎちゃうところがあって、上手に使わないと収拾がつかなくなっちゃう、というのは私も実感があります。
元々持ってる「シートとセル」というUIが優秀なうえに自作フォームも作れて、複数アプリの連携からファイルやフォルダ操作まで、Excel関係ないところまで手が届いちゃってなんでもできちゃうがゆえに、なんでもかんでもExcelで作れちゃう(作っちゃった)って部分があるんじゃないかなって。(私もキッチンタイマーとか作って遊んでたし。)
OfficeにVBAが実装された頃からすると現在の利用人口はものすごく増えているでしょうし、変数のスコープ(有効範囲)と一緒で、範囲が広ければ広いほど思いがけないことに発展したりするので、開発元としてはスコープを小さく、「表計算ソフトの範囲で使ってほしいな」と裾野の広がりにストップをかけたい方針なんじゃないかなと。で、範囲を超える場合は、自社製のRPAとかと組み合わせてほしいな、と。合理的ですよね。
どの手段を使うにせよ、1つの鍋のなかにすべてをぶち込むんじゃなくて、できるだけ機能は小さく切り出して部品化して組み合わせて使おうね、という考え方は大事だと思います。
なにはともあれ可読性の高いコードを心掛けたい
ブラックボックス化、属人化、このあたりのワードは悩みの種ではありますが、新しい手段だったらそうならないかと言ったら全然関係ないと思っていて。
どんな方法で、どんな言語で書くにしろ、他人や未来の自分のために、設計書の整備や読みやすいコードを心掛けるのが何より大事だと思います。(読めるように書いてあれば、言語はなんであれ関係ないですしね。)
読めない、わからないコードになってしまうなら、それはもう使い捨てと割り切ってしまうのもいいと思います。そのくらいの規模感がちょうどいいんじゃないかな。
自分の今後は
出版社さんとの打ち合わせで、次の本はどんなのにしましょうか、っていう話になると、「ExcelでもAccessでも良いですが、VBAでお願いします」って、現在進行形で言われています。商業出版の編集さんの生の声ですから、やっぱりまだ需要はあるのだなぁと。(そもそも私がよく書いているAccessのほうはVBAしかないのですが。)
私としては、需要があって執筆依頼をいただけるのであればVBAももちろん書くし、ほかの手段でも書いてって言われたら書けるように、引き続きいろいろ勉強していきたいと思っています。
長くなりました! 以上です!
2件のコメント
いつも楽しく拝見させていただいております。
型定義 の章のメモ欄に
” VBAで言うと、「Dim i Long」と整数型で宣言した変数には「i = 1」と代入しますが、「Dim ws Worksheet」とワークシート型で宣言したら「Set ws = Worksheets(“Sheet1”)」と代入の際にSetが必要になります。”
との記述がありますが、
「Dim i as Long」、「Dim ws as Worksheet」
の間違いですよね?
当方の勉強不足だったらゴメンなさい。
失礼しました。
「As」要ります! 早速修正いたしました。気がついてなかったので助かりました、ご指摘ありがとうございます!
コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)
YouTubeでQ&Aコンテンツを企画しています
運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。