---
tags: programming
---
# プログラミング完全未経験者のための Google Apps Script (GAS) 〜スプレッドシート編〜
プログラミングを全然やったことがないひとが Google Apps Script (GAS)をちょっと使ってみるための文書です。
(注:GASに実行権限を与えるところの説明は別に行っていたため、この文書でははぶいています)
## 0. GASをちょっと知ってるひとへのまえがき
この文書では、[`let`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let) や [`function`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/function) の機能を出来るだけ使わずに書いています。それらの機能が入門にはすこしむずかしいとおもわれたためです。後半になるまで、あえて`let` を使っていません。
## 1. GASのはじめかた 〜画面に文字を出してみよう〜
スプレッドシートの「ツール」→「スクリプトエディタ」をクリックします。

すると、Apps Script のページに移動するので、プロジェクトの名前を変更してみましょう。最初は「無題」とかってなってると思いますが、気分が出ないので「GASをつかってみる」というタイトルにしてみました。

ページの右に表示されているのが、Apps Script の「コード」です。
コードっていうのは、コンピュータさん(Google Spreadsheet さんとか)にやってほしいことを伝えるための「ことば」です。
<!--
Apps Script の「コード」は最初は下みたいな感じで、```function my function() { }``` だけが書かれています。
```javascript=
function myFunction() {
}
```
ちなみにこの意味は、`myFunction` っていう名前の関数<ファンクション>を書いていてその中身は大括弧開く`{`から大括弧閉じる`}`の間だけど中身は何もないよ、という意味です。
言い方を変えると何もしない関数が定義されています。
実際の Apps Script の見ためはちょっと違うかもしれません。2021年7月23日23時の実物は下みたいな感じです。

ちなみに一番左の、
```1```
```2```
```3```
```4```
っていう縦の数字は行番号です。
-->
これの2行目に、``` Logger.log("GAS ってなんだ?");``` っていう一行を足してみましょう。
```javascript=
function myFunction() {
Logger.log("GASってなんだ?");
}
```
できれば、コピーアンドペーストではなく、一文字ずつ、キーボードで入力してみましょう。
` ` ` ` `L` `o` `g` `g` `e` `r` `.` `l` `o` `g` `(` `"` `G` `A` `S` `っ` `て` `な` `ん` `だ` `?` `"` `)` `;`
<!--
計24文字です。細かいこというと上の例では行先頭に字下げのスペース` ` が2つあるので、26文字という言い方もできます。最後の`;`(セミコロン)もお忘れなく。-->
スペースは半角で入力する必要があります。アルファベットと記号は全て「半角英数」で書く必要があります。
さて、いきなりちょっと面倒でしたね。でも、書けましたか?
書けたら、Apps Script の画面の「保存ボタン」を押してみましょう。

保存できました? そうすると、「保存ボタン」のすぐ右の「実行ボタン」が押せるようになっているので押してみましょう。

すべてがうまく行けば、実行ログに「コード」の実行結果が出力されます。

もし``情報`` ``GAS ってなんだ`` っていう文字が画面の下の方の「実行ログ」というところに表示されてたら成功です🎉
<!--
ここで、文字をうち間違ってたりするとエラーが出たりします。例えば `Logger` の `g` を一個少なく、`Loger` と書いてたりすると下みたいになります。

赤文字で「`エラー`」「`ReferenceError: Loger is not defined`」 とか言われてます。
ここであせらず、英語を読むと、「Loger is not defined (Loger は定義されてないよ)」
と言ってますね。
慣れてくると、これを読むとすぐに、あー、なるほど文字を打ち間違えてたんだな。と問題の原因がわかったりします。
-->
<!--
`*` `*` `*`
さて、こんなのやってどうするのと思われたかもしれません。たしかに打ち込んだ文章がそのまま画面表示されただけです。
でもこれは、Google のアプリケーションたち、スプレッドシートやドライブやメールといった、Google のアプリケーションたちとお話をすることができた、という偉大な一歩なのです。喜びをかみしめていただけるとうれしいなと思います。
-->
## 1.1 で、```Logger.log()``` って何?
ちょっとくどいですが説明します。
まず、```Logger``` っていうのは、ログを出力するためのひとつの**クラス**です。
ん?
と、思われるのは普通だと思います。
まずログっていう言葉からあんまりなじみが無い人も多いかもしれません。ログっていう言葉は、語源的には航海日誌から来ています。航海する船乗り達が書く毎日の日誌を「ログ(Log)」と呼んでいました。今日は波が高かった、今日は東からの風が強かった、とかそういうやつです。記録を残しておくと、6月の半ばのエーゲ海沿岸は東の風が強い、というのがあとからわかったりします。
今でも英語で航海日誌のことをログ(Log)と呼びます。コンピュータの世界ではそれをまねしてコンピュータをうごかした記録のことをログと呼んでいます。```Logger``` のログはそういう意味です。
で、**クラス** ですが、クラスはある特定の目的の関数を集めたもの、関数を集めた引き出し、関数を集めた箱、のようなものです。ですので、```Logger``` はログに関係する関数を集めたものです。
先の例では、```Logger.log()``` と、```Logger``` というクラスに続いて ```.```(ドット)、```log()``` と書いていました。
これは、```Logger```というログに関する関数を集めたもののなかから、```log()``` という関数を使うよ。ということです。なので、この ```.```(ドット) は「その中の」のような意味です。
さて、最初の例をもう一度見直してみます。
```javascript=
function myFunction() {
Logger.log("GASってなんだ?");
}
```
<!--
```Logger.log``` のあとに、小括弧をひらいて ```(``` 、二重の引用符でくくって```"GASってなんだ?"``` と書いて、```)``` 小括弧を閉じて、`;` セミコロンで終わっています。-->
これは、`Logger` クラスの `log` という関数に ```"GASってなんだ?"``` という文章を渡している。という意味です。
言い換えると、```"GASってなんだ?"``` という文章をログとして表示することを、`log` 関数にお願いしているということです。
そのお願いを理解して、Google Apps Script (GAS) は画面下の「実行ログ」に「`GASってなんだ?`」と表示しました。
## 2. スプレッドシートを取得してタイトルを表示してみよう 〜 SpreadSheetApp クラスの getActiveSheets() と SpreadSheetクラスの getName()〜
次にスプレッドシートを取得してタイトルを表示する、ということをやってみましょう。
名前が取得できたかの確認のため、いま見ているスプレッドシートのタイトルを「GASをつかってみよう」にしておきましょう。

スプレッドシートのタイトル表示を行うコードがこれです:
```javascript=
function myFunction() {
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getName());
}
```
この文書では【コードの説明】でコードの中身を説明しています。最初は読まなくても大丈夫です。
> 【コードの説明】:
> 上のコードでは、[```SpreadSheetApp```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app) クラスの [```getActiveSpreadsheet()```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getactivespreadsheet) 関数を使って、このGASのコードの元になっているスプレッドシートを取得し、つづけて、[```SpreadSheet```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet) クラスの [```getName()```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#getname) 関数でスプレッドシートの名前を取得しています。
「実行ログ」に下の画像のように表示されると成功です🎉

## 3. スプレッドシートのシートを取得してみよう 〜 SpreadSheet クラスの getSheetByName() 〜
次に、シート名を指定して、シートを取得してみましょう。
シート名には、「列名シート」というのを使ってみます。

シート名を指定してシートを取得してそのシート名を表示する、ってことを行うコードがこれです:
```javascript=
function myFunction() {
Logger.log(SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("列名シート")
.getName()
);
}
```
この文書のなかの「コード」は結構よこにながくて、一行で書くと右の方が最後まで見えなくなってしまうので、「.(ドット)」の部分で改行しています。一行でよこながに書く場合と意味は同じです。
> 【コードの説明】
> ```SpreadsheetApp``` クラスの [```getActiveSpreadsheet()```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getactivespreadsheet) で元になるスプレッドシートを取得します。次に```SpreadSheet```クラスの [```getSheetByName(name)```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#getSheetByName(String)) 関数で、指定したシートを取得しています。最後に [`Sheet`](https://developers.google.com/apps-script/reference/spreadsheet/sheet) クラスの [`getName()`](https://developers.google.com/apps-script/reference/spreadsheet/sheet#getname) 関数でシートの名前を取得しています。
実行ログに下の画像のように表示されたら成功です🎉

## 4. スプレッドシートの列の内容を表示してみよう 〜 for文 と getRange() と getValues() と flat() 〜
A列のA1からA7に値を入れて、その値を取得してみましょう。
そのために、下の画像のような内容をさきほど作った「列名シート」の中に書いてみます。

表示するためのコードは以下です。
```javascript=
function myFunction() {
for (name of SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("列名シート")
.getRange("A1:A7")
.getValues()
.flat()
)
{ Logger.log(name); }
}
```
>【コードの説明】
>```.getRange("A1:A7")```
>```.getValues()```
>```.flat()```
>
>と書いた部分で、```A1```セルから```A7``` セルの値を一気に取得しています。
>
>まず、```Sheet``` クラスの [```getRange(a1Notation)```](https://developers.google.com/apps-script/reference/spreadsheet/sheet#getRange(String)) 関数で指定した範囲(`Range`)を取得し、つづけて、[`Range`](https://developers.google.com/apps-script/reference/spreadsheet/range)クラスの [`getValues()`](https://developers.google.com/apps-script/reference/spreadsheet/range#getValues()) 関数を使って指定した範囲の値の一覧(`Array`)を取得し、つづけて[`Array`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)クラスの、[`flat()`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) 関数で一覧の階層を平らにしています。
>
> これをきちんと理解するのは結構ややこしいので、
>
> ```.getRange("A1:A7")```
> ```.getValues()```
> ```.flat()```
>
> の3点セットで「指定した範囲の値の一覧がとれる」と覚えてしまって良いと思います。ここでは```A1:A7```を指定しているので、```A1```から`A7`までの値の一覧がいっぺんにとれます。
>
> それを、[```for(一覧の要素 of 一覧) { 繰り返すこと; }```](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of) 構文でひとつづつ取得して表示しています。
以下のように表示されたら成功です🎉

## 5. シートをコピーしてみよう 〜 copyTo() 〜
テンプレートとして以下のようなスプレッドシートを作成します。
ここでは「テンプレートのシート」をシート名として、中身に「われわれはテンプレートだ」と書いています。

「テンプレートのシート」というシートを「GASをつかってみよう」というスプレッドシートの中にコピーするためには以下のコードを書きます。
```javascript=
function myFunction() {
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("テンプレートのシート")
.copyTo(
SpreadsheetApp.getActiveSpreadsheet()
);
}
```
> 【コードの説明】
> [```Sheet```](https://developers.google.com/apps-script/reference/spreadsheet/sheet) クラスの [`copyTo(spreadsheet)`](https://developers.google.com/apps-script/reference/spreadsheet/sheet#copyTo(Spreadsheet)) 関数を使って、シートをコピーしています。指定したシートから指定したスプレッドシートにシートをコピーする関数です。
> ここでは、コピーする先のスプレッドシートとして、[```SpreadSheetApp```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app) クラスの [```getActiveSpreadsheet()```](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#getactivespreadsheet) でとってきたスプレッドシートをわたしています。つまりここでは、コピーする元と、コピーする先のスプレッドシートが同じもの、ということです。
下の画像のように「テンプレートのシートのコピー」というシートが新たに作成され、「われわれはテンプレートだ」という文章がコピーされていたら成功です🎉

## 6. 列名シートに書かれた分だけ、指定したシートをコピーしてシートの名前を変更してみよう 〜 setName() 〜
次に、列名シートに書かれた分だけ、指定したシートをコピーしてシートの名前を変更してみましょう。
以下の2つのことをおこなっています。新しいことはほとんどなく、これまでにやった、「3.シートを取得する」、「4.シートの中の列の中身を取得する」、「5.指定したシートをコピーする」、の組み合わせです。
1. 列名シートのA1:A7に書かれた列名を取得する
2. テンプレートのシートをコピーして、1で取得した列名に変更する
```javascript=
function myFunction() {
for (name of SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("列名シート")
.getRange("A1:A7")
.getValues()
.flat()
)
{
SpreadsheetApp.getActiveSpreadsheet()
.getSheetByName("テンプレートのシート")
.copyTo(SpreadsheetApp.getActiveSpreadsheet())
.setName(name);
}
}
```
新しくでてきたのは、いちばん最後12行目の [```setName(name)```](https://developers.google.com/apps-script/reference/spreadsheet/sheet#setnamename) だけです。
上に書いた実際のコードより下のコードの説明のほうが長くなってしまっていて、あきらかに下の説明の方がむずかしそうです。なので最初は読み飛ばしてください。いったいなにをやってるんだろう、と知りたくなったときに読むといいかもしれません。
>
> 【コードの説明】
> これまで使った関数を組み合わせています。ほとんどくり返しですがもういちどまとめて説明します。
>
> `SpreadsheetApp` クラス の`getActiveSpreadsheet()` 関数でコードをおいている元のスプレッドシートを取得して、`Spreadsheet` クラスの `getSheetByName(name)` 関数で `name` で指定したシートを取得して、`Sheet` クラスの `getRange(a1Notation)` 関数で `A1:A7`として指定した範囲を取得して、`Range` クラスの `getValues()` 関数で指定した範囲の値の一覧を取得して、`Array` クラスの `flat()` 関数で一覧の階層をひらべったくしています。その値の一覧を `for (一覧の要素名 of 一覧) { 繰り返したい内容; }` という構文<書き方> でくり返しています。
>
> くり返したい内容として`SpreadSheet`クラスの `getSheetByName(name)` で取得したシートを、`Sheet` クラスの `copyTo(spreadsheet)` で指定したスプレッドシートにコピーしています。
> コピーする先のスプレッドシートとして `SpreadsheetApp` クラスの `getActiveSpreadsheet()` 関数で、コードの元になっているスプレッドシートファイルを取得しています。
>
> そのあとで、[`Sheet`](https://developers.google.com/apps-script/reference/spreadsheet/sheet) クラスの [`setName(name)`](https://developers.google.com/apps-script/reference/spreadsheet/sheet#setnamename) 関数で、シートの名前を `name` で指定した名前に変更しています。
>
> いま `for (一覧の要素 of 一覧) { くり返したいこと; }` の中で、列名シートの`A1:A7` セルで指定したセルの一覧の要素を一つづつ、`name` という名前で取得しています。その `name` をつかってシートの名前を ```setName(name)``` 関数によって、 `name` 名前で取得されている`A1:A7` の各セルの中身の名前に変更しています。
>
下の画像のように「GASをつかってみよう」というスプレッドシートのなかに、「ある」「はれた」「ひる」「さがり」「いちばへ」「つづく」「みち」という7つのシートが追加されていて、中身は「われわれはテンプレートだ」と「テンプレートのシート」の中身が表示されていたら成功です🎉

## 7. `let` をつかうと? 〜 変数(へんすう)のチカラ 〜
この文書ではここまであえて [`let`](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let) という「**変数**をつくって、代入をおこなう機能」を使っていませんでした。ここで言う **変数** は小学6年の算数『文字と式』でまなぶ「変数」と同じで、`x` とか `y` といった名前のついたハコに値を入れる<代入する>ものです。
『文字と式』での変数は、いま1個 $400$ 円のケーキがあるとき、ケーキの個数を $x$ 個、代金を $y$ 円とする。すると、代金は $y = 400x$ になる、とかそういうやつでした。
6章まででひとまず動くコードができたので、「6.列名シートに書かれた分だけ、指定したシートをコピーしてシートの名前を変更してみよう」のコードを `let` で変数をいくつかつくって書きかえてみます。
ここで `let` をつかって書きかえる目的は「コードをすっきりさせること」です。
```javascript=
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let names = ss.getSheetByName("列名シート").getRange("A1:A7").getValues().flat();
for (name of names) {
ss.getSheetByName("テンプレートのシート").copyTo(ss).setName(name);
}
}
```
すっきりした、と感じられるでしょうか?
たとえば、`let ss = SpreadsheetApp.getActiveSpreadsheet();`
の行の意味は、
`SpreadsheetApp.getActiveSpreadsheet()` を `ss` とする
です。
ケーキの代金を$y$ 円とする、ケーキ1個が $400$ 円、ケーキの個数を $x$ とする。それを文字式でいうとケーキの代金は、 $y = 400x$ であらわせる。というのと、コードのなかで `let` を使うときの気分は同じです。
ちなみにこの `let` は英語で数学をするとき、変数を、
> let $x$ be the number of cake,
のように let を使って作ることからきています。
なお、上のコードの書きかえは、あくまで一例です。
ここでは「すっきりした」と思えることを目的として、
「`let` を使って、同じものが何回も出てくるときに同じ変数をつかっている」
だけなので、自分がすっきりする書き方でかければ、どんな方法でもよいと思います。
`let` の書き方がわからないとか、`let` を使うとわけがわからなくなる、とかだと本末転倒です。つかいたくなったときにはじめて使ってみればよいとおもいます。
## 8. スプレッドシートの複数列の内容を表示してみよう 〜 getRange(). getValue() で flat() を使わないとどうなる? 〜
「4. スプレッドシートの列の内容を表示してみよう」で、ある列の内容を表示するということを行いましたが、複数の列に対してなにかをしたい場合はどうすればよいでしょう。
Aの列の右に、下の画像のようにBの列を追加して、これらの列を表示する方法を考えてみましょう。

複数列の表示を行うコードは以下です。7章 「7. `let` をつかうと?
」で `let` を使ってみましたので、この章以降は `let` も使っています。
```javascript=
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let table = ss.getSheetByName("列名シート").getRange("A1:B7").getValues();
for ([sheet_name, dona] of table) {
Logger.log(sheet_name);
Logger.log(dona);
}
}
```
コードの説明は以下ですが、またすごく長くなっていてコードよりむずかしそうに見えるので最初は読み飛ばしてよいとおもいます。なにをやってるか知りたくなったときによむといいかもしれません。
> 【コードの説明】
> まず `Sheet` クラスの
> [```getRange(a1Notation)```](https://developers.google.com/apps-script/reference/spreadsheet/sheet#getRange(String)) 関数に指定する範囲を変更しています。`A1:A7` という `A`列だけの1列7行ではなく、`A1:B7` という2列7行の範囲を指定しています。
> その次ですが [`Range`](https://developers.google.com/apps-script/reference/spreadsheet/range)クラスの [`getValues()`](https://developers.google.com/apps-script/reference/spreadsheet/range#getValues())関数のあとに続けて使われていた `flat()` がなくなっています。
> 代わりに、
> `for (一覧の要素 of 一覧) {`
> ` くり返したいこと;`
> `}`
> の「一覧の要素」の部分が変わっています。
>
> `for ([sheet_name, dona] of table) {`
>
>`}`
> のように、角がっこ **[ ]** でかこんで **,** (コンマ) で区切られた2つの名前 `sheet_name, dona` が書かれています。
> このように、角かっこでかこんで複数の名前を **,** (コンマ) で区切ることで、複数の列の中身を取得しています。今回、`A1:B7` のように**2列**の範囲を指定しているので、`[sheet_name, dona]` のようにコンマで区切った2つの名前を指定しています。
>
> 例えば、`A1:C7`と3列指定する場合は `[a,b,c]` のように3つの名前をコンマで区切って指定することになります。指定する名前は自分にとってわかりやすい名前であればなんでもかまいません。
>
> ここでイラストでも説明してみます。
>
> まず、`A1:B7` で指定した範囲のテーブルを一覧とすると、一つの要素は下の図の 青のワク線の各行になります。それぞれ1行2列のセルです。上のコードの`for` 文ではこの青のワク線の部分が一つの要素になります。
>
>ですが、この青線で囲まれた各行には、さらに以下の赤のワク線の2つのセルが含まれています。一覧の要素のなかにさらに要素がある状態です。
> 
> そのため一つのセルの中身を要素として指定したい場合には、`for (一覧の要素 of 一覧) {繰り返したいこと;}` の文の`一覧の要素` の部分で、`[1つ目の要素,2つめの要素]`のように小カッコ **( )** の中で角カッコとコンマを使って区切る必要があります。
>
> 角カッコとコンマを使って図示してみると、以下のようになります。
> 
さて、今回のコードを実行した結果、実行ログに以下のように表示されると成功です🎉

## 9. 総まとめ: 列名シートのA列の分だけ指定したシートをコピーしてシートの名前を変更して、さらにB列の値をコピーしたシートに入れてみよう 〜 getRange() と setValue() 〜
さて、ここで「総まとめ」として、6のコピーしたシートのシート名を変更することに付け加えて、「列名シート」のB列の内容を、同じ行のA列のシート名を持つシートの「A4」のセルに入れてみることにしましょう。
具体的には、A,B列は前の8章の列をそのまま使います。

例えば「ある」という名前のコピー後のシートは以下のようになることを期待しています。

それを行うためのコードは以下のようになります。
```javascript=
function myFunction() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let table = ss.getSheetByName("列名シート").getRange("A1:B7").getValues();
for ([sheet_name, dona] of table) {
ss.getSheetByName("テンプレートのシート")
.copyTo(ss)
.setName(sheet_name)
.getRange("A4")
.setValue(dona);
}
}
```
> 【コードの説明】
> [`Sheet`](https://developers.google.com/apps-script/reference/spreadsheet/sheet) クラスの [`setName(name)`](https://developers.google.com/apps-script/reference/spreadsheet/sheet#setnamename) 関数のあとに、さらに [`Sheet`](https://developers.google.com/apps-script/reference/spreadsheet/sheet) クラスの [`getRange(a1Notation)`](https://developers.google.com/apps-script/reference/spreadsheet/sheet#getRange(String)) 関数と、それにつづけて [`Range`](https://developers.google.com/apps-script/reference/spreadsheet/range) クラスの [`setValue(value)`](https://developers.google.com/apps-script/reference/spreadsheet/range#setValue(Object)) 関数を使っています。
> この `getRange(A4).setValue(dona)` は `A4` の位置のセルを選択してそのセルに `dona` という
> `for ([一覧の要素1つめ, 一覧の要素2つめ] of table) {}` で取得した
> 一覧の要素の2つめを設定しています。この一覧の要素の2つめは B 列の各セルの内容が入っています。
以下の画像のように、A列のシートがコピーしたシートのシート名になり、さらに各シートのA4セルにB列の各セルの内容が入っていたら成功です🎉

とりあえずは以上です。おつかれさまでした。