2011年4月11日月曜日

Google Apps ScriptでGoogleドキュメントのスプレッドシートを操作する

はじめに

 「Google Apps Script」は、Googleドキュメントのスプレッドシートに搭載されているスクリプト機能です。これは発表当初、Google Appsの有料版(プレミア版)のみで利用可能であったため、「無償版のユーザーは使えない」と思っていた人も多いのではないでしょうが。が、現在では、無料で利用できるGoogleドキュメントでもスクリプトが使えるようになっています。これを利用し、Googleドキュメントのスプレッドシートを操作することができます。いわば、Excelなどの「マクロ」と同じ機能を提供してくれるのです。

 最近では、クラウド・アプリケーションとしてオフィスソフトが提供されるようになってきました。Googleの「Googleドキュメント」だけでなく、マイクロソフトが「Microsoft Office Web Apps」を公開するなど、本格的にWebへの移行が進められつつあります。一方、多くの人の認識と言えば、「スプレッドシートっていっても、せいぜい表を作って関数を設定できる程度でしょ? グラフやマクロなんかはまだまだできないんじゃない?」といったところではないでしょうか。

 しかし、知らない内にWebアプリケーションは進化しているのです。Googleドキュメントのスプレッドシートについていえば、既にベクターグラフィックの描画や各種グラフの作成、さらに文書への表やグラフの埋込みなど、スタンドアロン・アプリケーションのオフィスソフトと比べても遜色ないまでに進化しています。そして今、「スプレッドシートを自動制御するマクロ機能」についても使えるようになったのです。

Google Apps ScriptはサーバーサイドJavaScript!

 まず、このGoogle Apps Scriptというのがどういう言語なのか、簡単に説明しておきましょう。一口に言うなら「JavaScript+オブジェクトライブラリ」です。すなわち、JavaScriptに、Googleドキュメントを中心とした各種のサービスを操作するためのオブジェクトをまとめたライブラリを加えて提供し、これらのオブジェクトを利用することでサービスを操作できるようになっています。

Google Apps Scriptで非常に興味深いのは、これがクライアントサイドではなく「サーバーサイド」で実行される、という点です。JavaScriptは、基本的にクライアントサイドで実行されるスクリプト言語です。スプレッドシートを操作するにしろ、Webブラウザに表示されているシートの各要素をオブジェクトとして操作するのであれば、クライアントサイドだけで動いているように思うかも知れません。

 が、それはGoogle Apps Scriptの働きを見誤っているといわざるを得ません。これはただ単に「表示されているシートをJavaScriptで操作する」ためのものではありません。「Googleが提供するさまざまなサービスをJavaScriptで操作する」ためのものなのです。いえ、将来的なことを考えれば、Googleのサービスと限定する必要もないでしょう。

Webの世界に展開されるさまざまなサービス。それらをすべてスクリプトで操作し自動化する。Google Apps Scriptが目指すのは、そういう世界なのです。だからこそ、単にクライアントサイドだけで実行するのでなく、サーバーサイドに送られ、そこでさまざまなサービスにアクセスし処理できるようになっているのです。

スクリプトはどこに書く?

 では、実際にGoogle Apps Scriptを使ってみましょう。まず、Googleドキュメントにアクセスし、新規にスプレッドシートを作成してください。スプレッドシートの「ツール」メニューを見ると、そこに「スクリプト」という項目が用意され、その下に「管理」「挿入」「スクリプトエディタ」といった項目が表示されるはずです。これらの役割をざっと整理しておきましょう。

「管理」メニュー

 スクリプトを管理するためのものです。ライブラリなどからスクリプトを追加したとき、それらを編集したり実行したりすることができます。

 メニューを選ぶと、画面にパネルが現れ、そこで組み込まれているスクリプトを編集・実行・削除することができるようになります(デフォルトではスクリプトがないため、開いても何も表示されません)。

「挿入」メニュー

 「スクリプトギャラリー」という公開されたスクリプトのライブラリから、使いたいスクリプトを探して組み込むことができます。メニューを選ぶと、画面にパネルが現れます。このパネルでは、左側にスクリプトのジャンルが表示され、それをクリックすると右側にスクリプトのリストが表示されます。ここから使いたいものをインストールすることができます。

 現時点ではまだ、Googleが公開しているサンプルスクリプトだけしか用意されていないようですが、今後、ライブラリを充実させていけば、ここから使いたいものを探すだけでいろいろな機能を追加できるようになってくることでしょう。

 これは、「挿入」メニューにある「スクリプト」メニューを選んでも同様の画面を呼び出すことができます。

「スクリプトエディタ」メニュー

 スクリプトを自分で作成するための専用エディタを開きます。このスクリプトエディタは別ウインドウとして表示され、スクリプト編集のためのメニューとツールバー、編集エリアなどが用意されます。

 このスクリプトエディタは、スクリプトの入力を支援する機能が組み込まれており、記述された要素に応じて色分け表示したり、文法に応じて自動的にインデントをつけたりしてくれます。また入力中、オブジェクト名の後にドットを打つと、そのオブジェクトに用意されているメソッド類がポップアップして現れるなど、本格的な開発ツールに近い機能を提供してくれます。

スクリプトエディタを使う

 スクリプトの利用には、大きく2つの方法があります。1つは、「スクリプトギャラリー」を利用する方法です。これは、公開されたスクリプトをまとめて誰もが使えるようにしたものです。ここから使いたいものを選んで自分のスプレッドシートに組み込むことで、ノンプログラミングで各種の機能を組み込むことができます。

 もう1つの方法は、スクリプトエディタでスクリプトを書き、実行する方法です。先ほど説明したスクリプトエディタを使い、スクリプトを書いてその場で実行させることができます。スクリプトギャラリーの利用についてはそれぞれで実際に試してもらうとして、ここではスクリプトエディタを使ったスクリプト作成について説明していきましょう。

 先に説明したように、メニューを選んでスクリプトエディタを開いてください。デフォルトでは、次のようなスクリプトが記述されています。

function myFunction() {

}

 これは、関数の雛形となるものです。Google Apps Scriptで「スクリプトを書く」というのは、このように「関数を定義する」ということです。Google Apps Scriptでは、スクリプトはそれぞれユーザー定義関数として用意されます。そして利用する関数を指定して呼び出し、処理を行うのです。

メッセージを表示する

 ここでは、デフォルトで作成されているmyFunction関数をそのまま利用して簡単なサンプルを作ってみることにしましょう。次のようにスクリプトを追記してみてください。

function myFunction() {
  Browser.msgBox("Google Apps Scriptにようこそ!");
}

 わずか1行を追記しただけです。作成したら、スクリプトを保存してください。スクリプトエディタの「ファイル」メニューから「保存」を選び、適当な名前をつけて保存しておきましょう。

 では、このmyFunction関数を実行しましょう。エディタの上部にあるツールバーには、右向きの三角アイコンと、関数名を表示したコンボボックスがあります。ここで実行したい関数を選び、三角のアイコンをクリックすると、その関数がその場で実行されます。

 実行したら、ブラウザのウインドウを切り替え、スプレッドシートの表示に戻ってください。画面にアラートのようなパネルが現れ、メッセージが表示されます。パネルにある「OK」ボタンをクリックすれば、パネルは消え、スクリプトは終了します。

msgBoxメソッドについて

 今回使ったのは、画面に簡単なメッセージを表示する機能です。これは「Browser」というオブジェクトに用意されている「msgBox」というメソッドです。これは次のように呼び出します。

Browser.msgBox( メッセージ );

 引数に、表示したいメッセージをテキストとして用意します。これで、画面にアラートのようなパネルが現れます。ちょっとしたメッセージを表示するのに重宝する機能です。

入力ボックスを使う

 続いて、ユーザーから簡単な入力をしてもらうスクリプトを考えてみましょう。myFunctionを次のように修正してください。そしてスクリプトを実行してみましょう。

function myFunction() {
  var value = Browser.inputBox("名前を入力:");
  if (value != ""){
    Browser.msgBox(value + "さん、こんにちは!");
  } else {
    Browser.msgBox("何か入力してください。");
  }
}

 

 今回は、実行するとテキストを入力するフィールドがあるパネルが表示されます。ここにテキストを書いて[OK]を押すと、「○○さん、こんにちは!」と、入力したテキストを使って返事が返ってきます。何も入力しなければ「何か入力してください」と表示されます。

 ここでは、Browserオブジェクトの「inputBox」というメソッドを使ってます。これは次のような形で呼び出します。

変数 = Browser.inputBox( メッセージ );

inputBoxは、引数に渡したメッセージと入力フィールドをもったパネルを表示します。そしてOKしてパネルを閉じると、入力したテキストを返します。これで、簡単な入力と出力(表示)ができるようになりました。ごく簡単なスクリプトならすぐにでも作れそうですね!

選択されたセルの利用

 ユーザーとの基本的なやりとりができるようになったところで、いよいよ実際にスプレッドシートを操作してみることにしましょう。まずは、シートの基本となる「セル」の利用についてです。特定のセルの値を取得したり変更したりといったことを行ってみましょう。

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  var cell= sheet.getRange("A1");
  var value = cell.getValue();
  var cell2 = sheet.getRange("A2");
  cell2.setValue(value * 2);
}

Googleドキュメントのスプレッドシートは、複数のオブジェクトとしてGoogle Apps Scriptでは扱われます。基本的なオブジェクト類を整理すると次のようになります。

スプレッドシートの主なオブジェクト

オブジェクト名

概要

SpreadsheetApp

スプレッドシートアプリケーションのオブジェクトです。Googleスプレッドシートのアプリケーションそのものに関するメソッドなどが用意されます。

Spreadsheet

アプリケーションで開いているスプレッドシートのオブジェクトです。

Sheet

スプレッドシートにあるシートのオブジェクトです。1つのスプレッドシートに複数のシートを作成できますので、どのシートのオブジェクトを利用するかを考える必要があります。

Range

レンジ(シート内の一定の範囲)を示すものです。これは1つのセルからシートのセル全体をカバーするものまで自由に作成でき、これを通してセルにアクセスを行えます。

 セルは、Rangeというオブジェクトを使うことで利用できるようになりますが、このRangeを利用するためには、一定の手続に従う必要があります。

var ss = SpreadsheetApp.getActiveSpreadsheet();

 まず、SpreadsheetAppオブジェクトにある「getActiveSpreadsheet」で、現在選択されているスプレッドシートを取得します。このメソッドは、現在選択されているスプレッドシートのSpreadsheetオブジェクトを取得するメソッドです。

var sheet = ss.getSheets()[0];

Spreadsheetオブジェクトから、1ページ目のスプレッドシートのSheetオブジェクトを取得します。スプレッドシートに用意されているシートは「getSheets」で取得できます。このメソッドは、Sheetオブジェクトの配列のようになっているため、getSheets()[0]というようにして特定のSheetオブジェクトを取り出します。ここでは[0]として1枚目のシートのSheetを得ています。

var cell= sheet.getRange("A1");
var value = cell.getValue();
var cell2 = sheet.getRange("A2");
cell2.setValue(value * 2);

Sheetが取得できたら、セルを得るのは簡単です。Sheetの「getRange」メソッドを呼び出すことで、特定のセル範囲を扱うためのRangeオブジェクトが得られます。ここでは、引数に"A1","A2"というように指定することで、A1セルおよびA2セルのRangeを取得しています。

 こうして得られたRangeの値は、「getValue」「setValue」で取得・変更ができます。これにより、指定したレンジにあるセルの値を操作できるのです。

複数のセルの操作

 ここでは、Rangeで指定したのが1つのセルだけでしたから、単純にgetValue/setValueで値を操作できました。が、複数のセルを操作する場合はそうもいきません。getValueでは、選択された最初のセルの値しか取り出せないのです。このような場合には、「getValues」を使って、全セルの値をまとめて取得します。

function myFunction() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];
  var cells = sheet.getRange("A1:A3");
  var values = cells.getValues();
  var total = 0;
  for(var i in values){
    total += values[i] * 1;
  }
  Browser.msgBox("合計:" + total);
}

 これを実行すると、A1A3セルの合計を計算して画面に表示します。ここでは、次のようにしてセルの値をまとめて取得しています。

var cell= sheet.getRange("A1:A3");
var values = cell.getValues();

 範囲を指定してセルのRangeを取得する場合、指定の仕方はいろいろとあるのですが、最も分かりやすいのは、"A1:A3"というように範囲の2点(左上と右下)のセルをコロンで区切ったテキストとして指定する方法でしょう。こうして範囲指定することにより、getRangeで複数のセルをまとめてあつかうRangeが取得できます。そこから値を取得する「getValues」は、Rangeで指定した全セルの値を配列としてまとめて返します。後は、その配列から順に値を取り出して処理していけばいいわけです(ただし、複数列に渡って選択されている場合には修正が必要です。これについては後述します)。

選択されたセルの処理

 続いて、Rangeの範囲をあらかじめ決めておくのではなく、ユーザーが選択した範囲のセルを操作してみることにしましょう。これは、1列のみ選択した場合とそうでない場合で若干違いがあります。まず、1列のみ選択された場合を見てみましょう。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange()
  var values = range.getValues();
  var total = 0;
  for(var i in values){
    total += values[i] * 1;
  }
  Browser.msgBox("合計:" + total);
}

 選択された範囲は、SpreadsheetAppオブジェクトにある「getActiveRange」で得ることができます。後は、基本的に先のサンプルと同じです。getValuesで値をまとめて取得し処理するだけです。getActiveRangeを使えば、いちいちSheetを取得してRangeを取得してといった手順を省けるので、直接Rangeの範囲を指定するより処理が簡単です。

複数列に渡す範囲の処理

 ここまで行ってきたのは、基本的に「1列のみの処理」でした。しかし、表計算では複数列にまたがったデータを処理するのが一般的です。

 複数列に渡る範囲指定はgetValueの戻り値が二次元配列で返されるため注意が必要です。二重の繰り返しを用意して処理する必要があります。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange()
  var values = range.getValues();
  var total = 0;
  for(var i = 0;i < values.length;i++){
    for(var j = 0;j < values[0].length;j++){
      total += values[i][j];
    }
  }
  Browser.msgBox("合計:" + total);
}

 先ほどのスクリプトを修正したものです。ここでは、二重のforを使い、getValuesで取得した配列から値を取得しています。このやり方であれば、選択されたセル範囲が1列であろうと複数列であろうと、正しく値が計算できます。

セルをまとめて操作する

 セルの値を取り出して処理するだけならgetValuesですみますが、セルを操作するとなるとまた話は変わってきます。単純に、Rangeのセルをまとめて操作するなら、作業は簡単です。そのままRangeの設定を変更すればいいだけですから。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange()
  range.setValue("選択されたセル");
}

 これは、選択されたセルすべてに「選択されたセル」と表示させるものです。ここではgetActiveRangeで取得したRangeをそのままsetValueで設定しています。このRangeで示されているセルがいくつあろうと、すべてひとまとめにして操作を行うことができます。これは非常に簡単ですね!

セルの値を変更する

 問題は、11つのセルを個別に設定する必要がある場合です。この場合は、各セルのRangeを取得し、それぞれを操作することになります。では、11つのセルの値を設定するサンプルを考えてみましょう。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange()
  var cols = range.getNumColumns();
  var rows = range.getNumRows();
  var total = 0;
  for(var i = 1;i <= rows;i++){
    for(var j = 1;j <= cols;j++){
      var cell = range.getCell(i, j);
      cell.setValue(i + "," + j);
    }
  }
}

 これは、選択されたセルすべてに、そのセルの行・列の相対番号を表示する例です。セルをいろいろと選択して動作を確かめてみるとよいでしょう。

 ここでは、選択されているRangeの範囲を調べ、その範囲内のすべてのセルについてRangeを取得しsetValueする処理を行っています。まず選択されたRangeの範囲ですが、これは次のようなRangeのメソッドで調べることができます。

Rangeのメソッド

メソッド名

概要

getNumColumns

Rangeの列数を返す。

getNumRows

Rangeの行数を返す。

 これで行・列それぞれの数が分かります。後は繰り返しを使い、Range内のそれぞれのセルのRangeを取得し、setValueで値を設定します。

var cell = range.getCell(i, j);
cell.setValue(i + "," + j);

 セルの取得は、Rangeに用意されている「getCell」で行います。これは引数に列・行の相対番号(Range内の何番目にあるかという番号)を指定して呼び出します。これで、そのセルのRangeが得られますので、後はsetValueを呼び出し値を設定するだけです。

セルのプロパティを操作する

 続いて、セルのプロパティを操作してみましょう。例として、セルの背景色を変更してみます。ここでは、各セルの値をチェックし、プラスなら青、マイナスなら赤の背景色に設定してみましょう。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange();
  var cols = range.getNumColumns();
  var rows = range.getNumRows();
  var total = 0;
  for(var i = 1;i <= rows;i++){
    for(var j = 1;j <= cols;j++){
      var cell = range.getCell(i, j);
      if (cell.getValue() < 0)
        cell.setBackgroundColor("#fAA");
      else
        cell.setBackgroundColor("#AAf");
    }
  }
}

 基本的な流れは前回のサンプルとほぼ同じです。背景色を設定するのに、「setBackgroundColor」というメソッドを使っています。これは文字通り背景色を指定するものです。値は、CSSで使われる値(色の名前や16進数による指定)をそのまま使います。例えば、赤に設定するなら、「setBackgroundColor("red")」「setBackgroundColor("#F00")」というように値を設定します。

 このsetBackgroundColorのようなプロパティを操作するメソッドも、setValueなどと同様に、Rangeで指定されているすべてのセルに対して実行することが可能になります。例えば、このようにすれば、選択したすべてのセルの値と背景色がまとめて変更されます。

function myFunction() {
  var range= SpreadsheetApp.getActiveRange()
  range.setBackgroundColor("#fAA");
  range.setValue("選択されたセル");
}

Rangeは、このようにそれが示すセルが1つでも複数でも同じようにメソッドを呼び出すだけで処理を実行することが可能です。

メニューを作成する

 最後に、作成したスクリプトを簡単に利用できるようにする方法として、オリジナルのメニューを作成する方法について説明しておきましょう。メニューはSpreadsheet単位で独自に組み込むことができます。これはSpreadsheetにある次のようなメソッドを呼び出して行います。

Spreadsheet.addMenu( メニュー名 , 配列 );

 第1引数には表示するメニュー名、第2引数には組み込むメニューに関する情報をまとめた配列を渡します。この配列には、組み込むメニューの名前と実行する関数名を次のような形でまとめておきます。

[
    { name: メニュー項目名 , functionName: 関数名 },
    { name: メニュー項目名 , functionName: 関数名 },
    ……必要なだけ記述……
]

 これで、nameに指定した名前のメニュー項目が作成され、そのメニューを選ぶと、functionNameに指定された関数が実行されるようになります。

 このaddMenuによるメニューの組み込みは、スプレッドシートを開いたときに実行するのが最もベストでしょう。これには「onOpen」というイベントを利用します。これはGoogleスプレッドシートに用意されているイベントで、スプレッドシートを開く際に、onOpen関数を自動的呼び出すようになっています。これを利用することで、スプレッドシートを開くとメニューが自動的に設定されるようにできます。

 では、実際に簡単なメニューを組み込むサンプルを作ってみましょう。

function onOpen() {
  var arr = [
    {name: "背景色の設定", functionName: "changeBgColor"},
    {name: "文字色の設定", functionName: "changeTxtColor"}
  ];
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  spreadsheet.addMenu("マイメニュー", arr);
}

function changeBgColor() {
  var value = Browser.inputBox("背景色を入力:");
  if (value != ""){
    var range= SpreadsheetApp.getActiveRange();
    range.setBackgroundColor(value);
  }
}

function changeTxtColor() {
  var value = Browser.inputBox("テキスト色を入力:");
  if (value != ""){
    var range= SpreadsheetApp.getActiveRange();
    range.setFontColor(value);
  }
}

 スクリプトエディタでスクリプトを記述し、それを[ファイル]メニューの[保存]で保存してください。そして、一度スクリプトエディタとスプレッドシートを閉じ、再び開いてみましょう。メニューバーの[ヘルプ]の右側に、自動的に[マイメニュー]というメニューが追加されます。

 このメニューには、選択されたセルの背景色とテキスト色を変更するメニュー項目を用意してあります。メニューを選んで色の値を入力すると、選択されたセルの背景色やテキスト色が変更されます。背景色はsetBackgroundColorで変更できますが、テキストの色はRangeの「setFontColor」というメソッドで変えることができます。使い方はsetBackgroundColorと同じですので、それぞれで試してみてください。

 

まとめ

 以上、Google Apps Scriptの基本的な使い方から、セル関係のごく初歩的な操作までを一通り説明しました。一読してどのような印象を持ったでしょうか。既にExcelなどのマクロを使ったことがあれば、感覚的にほぼ同じような形でシートやセルを操作できることに気がついたでしょう。使用する言語はJavaScriptですが、既にExcelなどを使いこなしているユーザーのことを考え、それほど違和感なくスクリプトが書けるように配慮しているのでしょう。

 現時点で、スクリプトエディタも、またシートやセルの実装についても、ほぼ基本的なものは一通り揃っており、すぐにでも実用として使えるようになっています。とはいえ、もちろんまだ足りない機能もあります。例えば、Excelではマクロの自動記録機能などがあり、これで簡単にマクロを生成できましたが、こうした機能はまだGoogle Apps Scriptにはありません。またスクリプトエディタも、デバッグ環境などの整備は今後の課題と言えるでしょう。

 しかしながら、Webアプリケーションでありながら、こうした実用レベルのスクリプト言語が搭載されたという点は、高く評価されるべきでしょう。単なる表計算としてしか使っていないのであれば、基本的な表の機能と関数程度が揃っていれば十分でしょうが、本格的な業務にExcelなどを使っているユーザーにとって、「マクロすらない表計算ソフト」は貧弱でとても移行する気にはなれません。Google Apps Scriptにより、Googleドキュメントはようやく「本格的な業務利用に耐えうるスプレッドシート」と認められるようになった、と言えるのではないでしょうか。

 

0 件のコメント:

コメントを投稿