どうも。つじけ(tsujikenzo)です。2020年11月から始まりましたノンプロ研GAS初級講座7期ですが、このシリーズでは講座中では時間の都合でお伝えできなかったことなどを、全6回+おまけという感じでお届けしております。本日は5回目でございます。
前回のおさらい
前回は「オブジェクト」について学びました。前半は「プロパティ」と「メソッド」というオブジェクトの書き方(オブジェクトリテラル)と操作について学びました。後半ではJavaScriptやGASはオブジェクト群で構成されており、そのオブジェクト群(クラスと言います)を呼び出すだけで、様々なデータ型やサービスを操作することができるというお話でした。
DAY5補講
それではDAY5を振り返ります。今日は「スプレッドシート・シート・セルの操作」についてでした。今日の肝となるキーワードは『3つ』です。
SpreadSheetオブジェクト
SpreadSheetを掴む方法は『3つ』です。トップレベルのオブジェクトSpreadSheetAppに続けて記述します。
- アクティブなスプレッドシートを取得 =バインドしているスプレッドシート
- URLで取得
- IDで取得
SpreadSheetのURL
SpreadSheetのURLを指定する時はブラウザに表示されているURL全部をコピペして問題ありません。
>https://docs.google.com/spreadsheets/d/{ID}/edit#gid=0
ただ、厳密に言うとSpreadSheetのURLは/editまでです。 #移行はシートIDを示すものになっており、デフォルトで用意されているシートのIDは#gid=0で、シートを追加すると新しいIDが付与されていることが分かると思います。(このシートIDでシートが掴めるといいのですが、そのようなメソッドが用意されていないので、別途ライブラリを後日ご紹介します。)
Sheetオブジェクト
Sheetを掴む方法も『3つ』です。SpreadSheetオブジェクトに続けて記述します。
- シート名で取得
- 配列を取得しインデックスで指定
- アクティブなシートを取得 =バインドしているスプレッドシートのアクティブなシート
3つありますが、特別な理由が無い場合はほとんどシート名で取得するような気もします。
“` const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetByName = ss.getSheetByName(‘シート1’);
“`
シートが何枚あっても構わないけど、常に先頭のシートを取得したい場合は配列タイプで取得する場合も。
“` const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetByIndex = ss.getSheets()[0];
“`
シートが絶対1枚しかない場合はアクティブシートで取得することがあります。(後はonEdit()トリガーの時に使うと便利かもしれません)
“` const sheetActive = SpreadsheetApp.getActiveSheet(); “`
なぜ.getActiveSheet()がトップレベルオブジェクトのSpreadSheetAppから呼び出せるのか
getActiveSheet()メソッドはシートを掴む為のメソッドなので、シートの一つ上の階層であるSpreadSheetオブジェクトに対してじゃないのか?と言う疑問があると思います。(無いですか💦)
今までの流れですと、シートを掴むなら、
“` SpreadSheetApp.getActiveSpreadSheet().getActiveSheet()
“`
のように、SpreadSheetApp(トップレベルのオブジェクト)→SpreadSheet→Sheetという順番で掴まないといけないはずです。(マトリョーシカみたいな)
>答え:SpreadSheetAppにメンバーとして定義されてるから
リファレンスで確認してみましょう。
特に理由は書いていないようですね。恐らく.getActiveSheet()メソッドの内部にはちゃんと.getActiveSpreadSheet()が書かれていて、私たちは省略できるんだと思います。(私もGASのクラスを作った人じゃないので裏は取れませんが。)
Rangeオブジェクト
Rangeを掴む方法も『3つ』です。Sheetオブジェクトに続けて記述します。
- アドレスで取得
- 行番号,列番号,行数,列数で取得
- データ範囲を取得
これは場面によってどれも使う機会が出てくるので、3種類慣れていた方がいいです。変則的なものは無いので、使えば使うほど慣れると思います。比較的わかりやすいので補足は割愛します。
A1形式と絶対的なR1C1形式
ExcelのR1C1方式に慣れている方への補足ですが、GASではRangeを掴む方法として相対位置としてのR1C1形式は使えません。(A1セルをR1C1とする絶対的なRangeとして取得する方法はありますが、Rangeオブジェクトを相対位置としてR1C1方式で掴むメソッドは用意されていません。)
しかしこれもアドレスで取得(A1形式)で統一した方がいいので、R1C1形式でRangeを掴む意味はありません💦(Sheetオブジェクト.getRange(‘R1C1’)なんて書き方はしないという意味です。Sheetオブジェクト.getRange(‘A1’)でよいでしょう。)
.getDataRange()メソッドはA1から
講座ではセルに値が入力されているセルを起点として終わりまでの範囲を取得すると言いましたが、間違いでした💦正しくはA1を起点とした~となります。
シートに何も値が入力されていない時は.getDataRange()は’A1’を返します。これは.getDataRange()メソッドがA1を起点としているからですね。失礼いたしました💦
セルの値
セルに入力されている値の取得はgetValue()かgetValues()メソッドです。対象が単体のセルか複数のセルかによってメソッドが変わります。
これらのメソッドはRangeオブジェクトに対して使います。(言い換えるとgetValue()とgetValues()メソッドはRangeオブジェクト(クラス)のメンバーです。)getValue()メソッドは単体のセルに対して有効なメソッドなので、Rangeオブジェクトも必然と単体のセルであることがイメージできると思います。
“` const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheets()[0]; sheet.getRange(‘A1’).getValue(); //A1に入力されている値を取得する
“`
対象が複数のセルに渡る場合、Rangeオブジェクトもセル範囲を示す記述であることがポイントです。
“` const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheets()[0]; sheet.getRange(1,1,5,5).getValues(); //A1:E5に入力されている値を2次元配列で取得する
“`
複数のセル範囲のRangeオブジェクトに対して、getValue()をしてしまうミスなどはよくありますので、気を付けてください。(エラーは出ないけど何もログを返さない)
“` const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheets()[0]; sheet.getRange(1,1,5,5).getValue(); //
“`
この4つのメソッドは単体か複数か、getかsetかという組み合わせになっていますので、覚えやすいです。大事なのは「それぞれのメソッドの対象となるRangeオブジェクトはどう指定すべきなのか」というポイントです。復習頑張ってください!
getValue() getValues()
setValue() setValues()
再頻出コード
色々説明しましたが、再頻出コードはこの2つかもしれません。これから沢山書くので自然と覚えると思いますが、とりあえず一つだけでも覚えて帰りたい時にはおススメです。
“` sheet.getDateRange().getValues(); sheet.getRange(row, column, array.length, array[0].length).setValues(array); “`
いつか使うかもしれないメソッド達
あまり使わないかもしれないけど知ってると便利なメソッドです。
Range.getA1Notation()・・・・セル範囲をA1形式で取得
Range.getDisplayValue()・・・Dateオブジェクトで入力されている”12月20日”などの値を見た目のまま取得する
Range.getFormula()・・・表示されている式の結果(値)ではなく、式(Formula)を取得する
Range.getFormulaR1C1()・・・Formulaを取得した際にセル範囲があればR1C1形式で表示する。
“` console.log(range.getFormula()); //=SUM(A2:A3) console.log(range.getFormulaR1C1()); //=SUM(R[-2]C[0]:R[-1]C[0]) “`
意外と知らないappendRow()
何も考えなくても最終行にレコードを追加してくれる超イケメンなメソッド()です。引数として渡すのは1次元配列ですからね!これはいつか絶対ハマるポイントです。
後、スプレッドシートにArrayFormula関数を使っていると思うような動作をしない場合がありますので要注意だそうです。(umeさんありがとうございます。)
他にも便利そうなメソッドは沢山ありますが、使い方や使う場面は人それぞれなので、公式リファレンスと仲良くなることを心掛けてみてください。どのクラスにぶら下がっていて、戻り値が何かは他人が書いたコードを理解するうえで上達する近道です。(ちなみに3カ月前の自分は他人だと言うことを覚えておいてくださいw)
まとめ
以上で、DAY5の振り返りと補足でした。今日のキーワードは『3つ』とお伝えしましたが、SpreadSheetオブジェクトもSheetオブジェクトもRangeオブジェクトも、掴み方は3つずつです。沢山覚えないといけないことがありそうですが、「3つずつ」って思うとなんだか気が楽ですね。(私の経験です💦)
VBAと違ってトップレベルオブジェクトや上層のオブジェクトを省略しないのもGASの特徴です。そのせいで記述が長くなったりしません。後で読みやすいコードなのが一番です!(そういうとこGASは真面目なので本当はチャラくないですw)
さて、次回はいよいよ最終回『スプレッドシートの操作(実践編)』です。最終回はスプレッドシートのデータの持ち方や、心構えのような内容も含まれますので、手を動かす内容的には今日の第5回目の方がボリューミーです。なので今日の内容を乗り越えられれば大丈夫です!頑張りましょう~。