ーーーーーーーーーーーーーーーーーーーーー2026年4月19日執筆ーーーーーーーーーーーーーーーーー
- この記事のPodcast
- はじめに:現代の業務自動化におけるGoogle Apps Scriptの役割
- 階層構造の理解:コンテナとしてのオブジェクトモデル
- SpreadsheetApp:全ての操作のゲートウェイ
- Class Spreadsheet:ファイル全体の統括管理
- Class Sheet:データの器を構成する
- Class Range:セル操作の精密な制御
- 1始まりの座標と0始まりの配列:混乱を避けるための知識
- V8エンジンの特性を活かした最適化
- パフォーマンスの黄金律:一括処理(Bulk Operations)
- 高度な管理機能:データの保護と検証
- 特殊なデータソースとの連携
- 結論:基礎の徹底が高度な自動化を実現する
- 参考資料
- はじめに
- スプレッドシートサービスとは?
- スプレッドシートの読み込み及びGASの起動
- スプレッドシート(Spreadsheet)のメソッド
- シート(Sheet)メソッド
- Rangeオブジェクトのメソッド
- おわりに
この記事のPodcast
下記のPodcastは、Geminiで作成しました。
はじめに:現代の業務自動化におけるGoogle Apps Scriptの役割
Google Apps Script(以下、GAS)は、Google Workspaceの利便性を飛躍的に向上させるクラウドベースのプログラミング環境です。特にGoogle スプレッドシートとの連携は、データの収集、分析、報告といった日常業務の自動化において中核的な役割を担っています 。スプレッドシートを単なる表計算ソフトとしてではなく、一つのデータベースやアプリケーションのプラットフォームとして活用するためには、その内部構造をプログラムの視点から理解する必要があります 。
本稿では、GASを用いてスプレッドシートを操作する際に最も重要となる3つの要素、「スプレッドシート(Spreadsheet)」「シート(Sheet)」「範囲(Range)」について解説します。これらは階層構造を形成しており、この概念を正確に把握することが、エラーのない効率的なスクリプト作成の第一歩となります 。2020年に導入されたV8ランタイム以降、GASの処理能力は大幅に向上しましたが、その性能を最大限に引き出すためには、オブジェクトへのアクセス方法やデータの取り扱いに関する最新の知識が不可欠です 。
階層構造の理解:コンテナとしてのオブジェクトモデル
GASにおけるスプレッドシート操作は、常に特定の「階層」を意識して行われます。これは、ファイルの中にタブがあり、タブの中にセルがあるという現実のスプレッドシートの構造を、そのままプログラム上のオブジェクトとしてモデル化したものです 。
この階層構造は、上位から順に「SpreadsheetApp」「Spreadsheet」「Sheet」「Range」という4つの主要なクラスで構成されています。それぞれの役割と関係性を整理すると、以下のようになります。


| 階層レベル | クラス名 | 現実世界での比喩 | 主な役割 |
| 第1層 | SpreadsheetApp | アプリケーション本体 | サービスの起動、ファイルの新規作成、アクティブなファイルの取得 |
| 第2層 | Spreadsheet | スプレッドシートファイル(1つのExcelブックに相当) | ファイル名の変更、シートの追加・削除、権限管理 |
| 第3層 | Sheet | シートタブ(1つのワークシートに相当) | 行や列の挿入、シートの保護、特定の範囲の選択 |
| 第4層 | Range | セルまたはセル範囲(1つ以上のマス目) | 値の読み書き、背景色の変更、書式設定 |
この構造を理解していないと、「セルの色を変えたいのに、ファイル全体を操作する命令を使ってしまう」といった間違いが発生します 。プログラムを書く際は、常に「今、自分はどの階層を操作しているのか」を意識することが重要です。
SpreadsheetApp:全ての操作のゲートウェイ
SpreadsheetAppは、GASからGoogle スプレッドシートのサービスそのものにアクセスするための最上位クラスです 。スプレッドシートを操作するスクリプトは、ほぼ例外なくこのクラスの呼び出しから始まります。
スプレッドシートを開く手法の選択
スプレッドシートをプログラムで制御するためには、まず対象となる「ファイル(Spreadsheetオブジェクト)」を特定し、取得しなければなりません。これには主に以下の3つの方法があります。
- getActiveSpreadsheet(): スクリプトが紐付いている(コンテナバインド)スプレッドシートを取得します 。最も手軽で、ツールとして配布する際によく使われます。
- openById(id): スプレッドシートの固有IDを指定して開きます 。IDはURLの一部(
/d/と/editに挟まれた文字列)から取得できます。他のファイルを参照する場合に必須となります。 - openByUrl(url): スプレッドシートの完全なURLを指定して開きます 。直感的ですが、URLが変更された場合に機能しなくなるリスクがあります。
これらのメソッドを実行すると、次の階層であるSpreadsheetオブジェクトが返されます 。なお、スクリプトを初めて実行する際には、これらの操作に対する承認(OAuthスコープの許可)が求められます 。
Class Spreadsheet:ファイル全体の統括管理
Spreadsheetクラスは、一つのファイル全体に関連する設定や、その中に含まれる「シート(Sheetオブジェクト)」の管理を担います 。
シートの取得と整理
一つのファイルには複数のシート(タブ)が存在できるため、目的のシートを正確に取得するスキルが必要です。代表的なメソッドには以下のものがあります 。
- getSheetByName(name): 指定した名前のシートを取得します。シート名が変更されるとエラーになるため、運用上の注意が必要です。
- getSheets(): ファイル内の全てのシートを配列形式で取得します。ループ処理で全てのシートを検査する場合や、一番左のシートを特定する場合に使用されます。
- insertSheet(name): 新しいシートを挿入します。オプションを指定することで、既存のシートをテンプレートとしてコピーすることも可能です。
- deleteSheet(sheet): 指定したシートを削除します。
ファイルレベルの設定項目
ファイル全体に対するメタ情報の取得や操作もこのクラスで行われます。例えば、getName()でファイル名を取得したり、rename(newName)で名称を変更したりすることができます 。また、getSpreadsheetLocale()やgetSpreadsheetTimeZone()は、日付や数値を扱うプログラムにおいて、地域の違いによる誤作動を防ぐために重要な情報を返します 。
Class Sheet:データの器を構成する
Sheetクラスは、スプレッドシート内の個別のタブを操作するためのクラスです 。ここでは、行や列の追加といった「表の構造」に関する操作が中心となります。
動的なデータ追加と構造変更
初心者が最初に覚えるべき非常に強力なメソッドがappendRow(rowContents)です 。これは、シート内の既存データがある最終行を自動的に探し、その次の行に配列として渡されたデータを一行追加するものです。
JavaScript
// A列に日付、B列に項目名、C列に金額を追加する例
const sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow();
このメソッドを使えば、行番号を意識することなくデータを蓄積していくことが可能です 。一方で、表の途中にデータを挿入したい場合は、insertRowBefore(position)やinsertRowsAfter(position, howMany)といったメソッドを使用します 。
シートの保護とUIの制御
実務的なスクリプトでは、ユーザーによる誤操作を防ぐためにprotect()メソッドを使って特定のシートを保護することがあります 。また、hideSheet()やshowSheet()を用いることで、計算用の隠しシートを普段は見えないように制御するといった、ユーザーインターフェースとしての工夫も可能です 。
Class Range:セル操作の精密な制御
スプレッドシート操作の最小単位であり、最も頻繁に使用されるのがRangeクラスです 。セルの値を取得する(Read)、値を書き込む(Write)、書式を設定する(Format)といった操作は全てこのクラスを通じて行われます。
セル範囲の指定(getRange)
Rangeオブジェクトを取得するには、Sheetオブジェクトに対してgetRange()メソッドを呼び出します 。このメソッドには複数の引数のパターンがあり、状況に応じて使い分ける必要があります。
| 指定方法 | 記述例 | 特徴 |
| A1記法 | getRange("A1:C10") | 文字列で直感的に範囲を指定できます 。 |
| 座標指定 (1セル) | getRange(row, col) | 行と列の番号(1から開始)で指定します 。 |
| 座標+行数 | getRange(row, col, rows) | 開始地点から指定した行数分を範囲とします 。 |
| 座標+行数+列数 | getRange(row, col, rows, cols) | 矩形の範囲を数値で厳密に指定できます。ループ処理と相性が良いです 。 |


1始まりの座標と0始まりの配列:混乱を避けるための知識
GASでスプレッドシートを扱う際、初心者が最も陥りやすい罠が「インデックス(数え方)」の違いです 。
スプレッドシートの「1-based」
スプレッドシート上の座標(行番号・列番号)は、常に「1」から始まります 。A1セルは「1行目の1列目」であり、getRange(1, 1)と記述します。これは人間が日常的に使う数え方と同じです 。
JavaScript配列の「0-based」
一方、GASのベースであるJavaScriptにおいて、データを格納する「配列」のインデックスは「0」から始まります 。getValues()を使ってセル範囲のデータを取得すると、それは2次元配列になりますが、この瞬間に数え方が変わります。
JavaScript
// A1(1,1)のセルの値を配列で取得
const values = sheet.getRange("A1:B2").getValues();
// 配列内のアクセス
const a1Value = values; // A1は0行目の0列目として扱われる
この「1」と「0」のズレは、ループ処理でスプレッドシートに値を書き込む際に、計算間違いを引き起こす原因となります 。一般的に、スプレッドシートの操作(getRangeなど)には1始まりの数値を使い、取得したデータ(配列)の操作には0始まりの数値を使うというルールを徹底する必要があります 。
V8エンジンの特性を活かした最適化
最新のGAS実行環境であるV8エンジンは、Google Chromeと同じ高速化技術を採用しています 。しかし、スクリプトの書き方一つで、その恩恵を十分に受けられない場合があります。
隠しクラス(Hidden Classes)と最適化
V8エンジンは、JavaScriptの柔軟なオブジェクトに対して、内部的に「隠しクラス(Hidden Classes)」または「形状(Shapes)」と呼ばれる構造を割り当てることで処理を高速化しています 。オブジェクトが同じプロパティを同じ順番で持っている場合、V8は「同じ形状である」と判断し、最適化されたマシンコードを再利用します 。
パフォーマンスを低下させる書き方:
- オブジェクトを作成した後に、動的にプロパティを追加する 。
- ループの途中でオブジェクトの構造を変化させる 。
推奨される書き方:
- 初期化時に全てのプロパティを宣言し、必要に応じて
nullなどで埋めておく 。 - プロパティの追加順序を常に一定に保つ 。


パフォーマンスの黄金律:一括処理(Bulk Operations)
GASの実行速度が遅いと感じる場合、その原因のほとんどは「Googleのサーバーとスプレッドシートの間の通信回数」にあります 。セルを一つずつ読み書きする操作は、一回ごとに通信オーバーヘッドが発生するため、非常に非効率です。
getValues と setValues の活用
大量のデータを扱う際の鉄則は、getValue()やsetValue()をループの中で使わず、getValues()とsetValues()で一括処理することです 。
- 一括取得:
getValues()で対象範囲のデータを全て2次元配列としてメモリ上に読み込みます。 - メモリ内処理: JavaScriptの配列操作メソッド(
map,filter,forEachなど)を使って、高速にデータを加工します 。 - 一括書き込み: 加工後の2次元配列を、
setValues()を使って一度の通信でスプレッドシートに戻します。
この手法を採用するだけで、処理時間は数分から数秒へと劇的に短縮されることがあります 。


高度な管理機能:データの保護と検証
スプレッドシートを多人数で利用する場合、プログラムによる制御だけでなく、データの整合性を保つための機能も活用する必要があります。
入力規則と検証(Data Validation)
Rangeクラスには、セルに入力できる値を制限する「データの入力規則」を設定するメソッドがあります 。例えば、特定の値のリスト(プルダウン)を設定したり、数値の範囲を制限したりすることが可能です。これにより、スクリプトが想定外のデータを受け取ってエラーになるのを未然に防ぐことができます。
シートと範囲の保護(Protection)
Protectionクラスを使用すると、特定のユーザー以外が特定の範囲を編集できないようにロックをかけることができます 。
JavaScript
// 特定の範囲を現在のユーザー以外編集不可にする
const range = sheet.getRange("A1:B10");
const protection = range.protect().setDescription("編集禁止エリア");
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
このように、スクリプトで動的に権限を管理することで、ワークフローの安全性を高めることができます 。
特殊なデータソースとの連携
最近のアップデートでは、Google スプレッドシートを外部データベースのフロントエンドとして利用する機能が強化されています。DataSourceSheetクラスを使用すると、BigQueryやLookerなどの大規模なデータソースと直接連携し、GASからクエリの実行やデータの更新を制御することが可能です 。
これらの高度な機能も、基本となる「シート」や「範囲」の概念の上に成り立っています。基盤となるオブジェクトモデルを深く理解しているからこそ、新しい機能もスムーズに取り入れることができるようになります 。
結論:基礎の徹底が高度な自動化を実現する
本稿で解説した「スプレッドシート」「シート」「範囲」の3要素は、Google Apps Scriptにおける全ての操作の基盤となるものです。これらは単一の操作対象ではなく、互いに密接に関連し合う階層構造を持っています 。
効率的なスクリプトを書くためには、以下の3点を常に意識してください。
- 階層を正しく辿る: 目的の操作がどのクラスに属しているかを理解する。
- 配列をマスターする: 0始まりのインデックスと2次元配列の構造を理解し、一括処理を徹底する 。
- V8エンジンの特性に合わせる: オブジェクトの形状を安定させ、エンジンの最適化を妨げないコードを書く 。
GASの真価は、これらの基礎を組み合わせ、他のGoogleサービス(Gmail、カレンダー、ドライブなど)と連携させることで、複雑な業務フローを完全に自動化できる点にあります 。まずは一つのセル、一つのシートを思い通りに操ることから始め、徐々にその範囲を広げていってください。
参考資料
- SpreadsheetApp Class official documentation, https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app
- Google Apps Script SpreadsheetApp Class official documentation, https://developers.google.com/apps-script/reference/spreadsheet
- Class Spreadsheet methods and usage for beginners, https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
- Class Sheet methods and usage for beginners, https://developers.google.com/apps-script/reference/spreadsheet/sheet
- Class Range methods and usage for beginners, https://developers.google.com/apps-script/reference/spreadsheet/range
- Google Apps Script Sheet Class official documentation, https://developers.google.com/apps-script/guides/sheets
- Google Apps Script Sheet Class official documentation, https://workspace.google.com/products/apps-script/
- Google Apps Script Range Class official documentation, https://developers.google.com/apps-script/reference/document/range-element
- Google Apps Script Range Class official documentation, https://developers.google.com/apps-script/reference/document/range
- Google Apps Script Range Class official documentation, https://developers.google.com/apps-script/reference/spreadsheet/range
- GAS 入門 階層構造 初心者 分かりやすい 構成, https://zenn.dev/overflow_offers/articles/20220616-google-app-script-technique
- GAS getRange A1記法 数値指定 使い分け 詳しく, https://jp.tdsynnex.com/blog/google/gas-select-range-of-spreadsheet/
- GAS V8 engine getValues setValues speed optimization 2024 2025, https://www.thenodebook.com/node-arch/v8-engine-intro
- GAS V8 engine getValues setValues speed optimization 2024 2025, https://javascript.plainenglish.io/the-hidden-javascript-engine-optimization-that-makes-your-code-40-slower-26994e837830
- GAS V8 engine getValues setValues speed optimization 2024 2025, https://dev.to/parthchovatiya/understanding-the-v8-engine-optimizing-javascript-for-peak-performance-1c9b
- GAS V8 engine getValues setValues speed optimization 2024 2025, https://medium.com/@saravanaeswari22/v8-engine-internals-how-javascript-gets-compiled-e2716636c82f
- GAS getRange 4引数 使い方 初心者 違い, https://yyoshiblog.com/gas-getrange-range-specification/
- Google Apps Script 初心者 2次元配列 getValues 詳しく解説, https://hajiritsu.com/gas-s-getvalues/
- GAS V8 engine array index 1-based 0-based explanation for beginners, https://en.wikipedia.org/wiki/Zero-based_numbering
- GAS V8 engine array index 1-based 0-based explanation for beginners, https://medium.com/analytics-vidhya/array-indexing-0-based-or-1-based-dd89d631d11c
- GAS V8 engine array index 1-based 0-based explanation for beginners, https://www.thenodebook.com/node-arch/v8-engine-intro
- GAS V8 engine array index 1-based 0-based explanation for beginners, https://dev.to/alirezaebrahimkhani/be-careful-about-arrays-v8-engine-advice-1pmk
- GAS V8 engine array index 1-based 0-based explanation for beginners, https://medium.com/@stephenhuh/javascript-at-a-low-level-v8-engine-squeeze-every-cycle-with-arrays-944b9d46061
ーーーーーーーーーーーーーーーーーーーーー2021年9月2日執筆ーーーーーーーーーーーーーーーーー
はじめに
Google Apps Script入門第三弾として、スプレッドシート、シート、範囲について紹介します。
この記事を読むと、次の疑問について知ることができます。
- スプレッドシートサービスとは?
- スプレッドシートの読み込み及びGASの起動
- 学習するためのスプレッドシートファイルのコピーの作成
- GASの起動
- スプレッドシート(Spreadsheet)のメソッド
- アクティブなスプレッドシートの名前変更
- アクティブシートのコピー
- シート(Sheet)メソッド
- シート名の変更
- シートの列幅の変更
- Rangeオブジェクトのメソッド
- 範囲移動
- 範囲並べ替え
Google Apps Script入門(2)では、スプレッドシートのマクロとカスタム関数について学習してきました。
ここでは、スプレッドシート、シート、範囲などについて深堀していきます。
スプレッドシートサービスとは?
Google Apps Scriptで、Googleスプレッドシートを扱うためのここで解説する対象(オブジェクト)が4つあります。
- SpreadsheetAppオブジェクト
Googleスプレッドシートを扱う上で一番上の親になるオブジェクト - Spreadsheetオブジェクト
Googleスプレッドシートを扱うためのオブジェクト - Sheetオブジェクト
Googleスプレッドシート内のシートを扱うオブジェクト - Rangeオブジェクト
Googleスプレッドシート内のシート内の範囲、セルなどを扱うオブジェクト
そして、このオブジェクトを操作するためのそれぞれのメソッドが存在します。
GAS(Google Apps Script)で上述の操作をする場合に一般的な書き方は次のようになります。
function myFunction() {
const activSsheet = SpreadsheetApp.getActiveSpreadsheet();
}スプレッドシートの読み込み及びGASの起動
学習するためのスプレッドシートファイルのコピーの作成
GASでスプレッドシート、シート、範囲を学習していく上で必要なスプレッドシートファイルのコピーを作成します。
以下のURLをクリックすると、ドキュメントのコピー画面が表示されるので、「コピーを作成」をクリックします。
GASの起動
上部メニューの「ツール」⇒「スプリクトエディター」をクリックすると、無題のプロジェクトと言う名前のGASが立ち上がります。


スプレッドシート(Spreadsheet)のメソッド
スプレッドシートのメソッドとして、名前変更とコピーの2つににいて紹介します。
アクティブなスプレッドシートの名前変更
GASスクリプトの名前(無題のプロジェクト)を「アボカドの価格」に変更しておきましょう。
次に学習するために読み込んだGoogleスプレッドシートの名前「無題のスプレッドシート」の名前を「シアトルのポートランドでの2017年のアボカド価格」に変更します。
名前変更のメソッドは、次のように書きます。
実際のGASのコードは次にようにします。
function renameSpreadsheet() {
SpreadsheetApp.getActiveSpreadsheet().rename("シアトルのポートランドでの2017年のアボカド価格");
}
結果は次の通りです。


アクティブシートのコピー
次は、読み込んだGoogleスプレッドシートのシートが1つしかないので、そのコピーを作成します。
その時のメソッドはの書き方は次のようになります。
function duplicateAndOrganizeActiveSheet() {
//現在アクティブなスプレッドシートを取得し、それを変数mySSに代入
const mySS = SpreadsheetApp.getActiveSpreadsheet();
//現在アクティブなスプレッドシートのシートをコピーして、それを変数duplicateSheetに代入
const duplicateSheet = mySS.duplicateActiveSheet();
}
結果は次の通りです。


シート(Sheet)メソッド
シートのメソッドとして、シートの名前変更と列幅の変更の2つににいて紹介します。
シート名の変更
読み込んだGoogleスプレッドシートのシートがをコピーして。そのシート名を変更してみましょう。
その時のメソッドはの書き方は次のようになります。
function duplicateAndOrganizeActiveSheet() {
//現在アクティブなスプレッドシートを取得し、それを変数mySSに代入
const mySS = SpreadsheetApp.getActiveSpreadsheet();
//現在アクティブなスプレッドシートのシートをコピーして、それを変数duplicateSheetに代入
const duplicateSheet = mySS.duplicateActiveSheet();
// コピーしたシート名をSheet_シートIDに変更
duplicateSheet.setName("Sheet_" + duplicateSheet.getSheetId());
}
結果は次の通りです。


シートの列幅の変更
アクティブシートの列幅を変更して見易くしましょう。
その時のメソッドはの書き方は次のようになります。
function duplicateAndOrganizeActiveSheet() {
//現在アクティブなスプレッドシートを取得し、それを変数mySSに代入
const mySS = SpreadsheetApp.getActiveSpreadsheet();
//現在アクティブなスプレッドシートのシートをコピーして、それを変数duplicateSheetに代入
const duplicateSheet = mySS.duplicateActiveSheet();
// コピーしたシート名をSheet_シートIDに変更
duplicateSheet.setName("Sheet_" + duplicateSheet.getSheetId());
// コピーした新しいシートの列幅を1列から5列分文字幅により自動調整
duplicateSheet.autoResizeColumns(1, 5);
// コピーした新しいシートの最初の2行分を固定行として指定
duplicateSheet.setFrozenRows(2);
}
結果は次の通りです。


Rangeオブジェクトのメソッド
ここでは、Rangeオブジェクトのメソッドとして、範囲移動と範囲並び替えの2つを紹介します。
範囲移動
アクティブシート内の範囲を移動をしてみましょう。
その時のメソッドの書き方は次のようになります。
function duplicateAndOrganizeActiveSheet() {
//現在アクティブなスプレッドシートを取得し、それを変数mySSに代入
const mySS = SpreadsheetApp.getActiveSpreadsheet();
//現在アクティブなスプレッドシートのシートをコピーして、それを変数duplicateSheetに代入
const duplicateSheet = mySS.duplicateActiveSheet();
// コピーしたシート名をSheet_シートIDに変更
duplicateSheet.setName("Sheet_" + duplicateSheet.getSheetId());
// コピーしたあたらっシシートの列幅調整と2行の固定行の指定
duplicateSheet.autoResizeColumns(1, 5);
duplicateSheet.setFrozenRows(2);
// F列をC列に移動
var myRange = duplicateSheet.getRange("F2:F");
myRange.moveTo(duplicateSheet.getRange("C2"));
}
結果は次の通りです。


範囲並べ替え
アクティブシート内の範囲内の値の並び替えをしてみましょう。
その時のメソッドはの書き方は次のようになります。
function duplicateAndOrganizeActiveSheet() {
//現在アクティブなスプレッドシートを取得し、それを変数mySSに代入
const mySS = SpreadsheetApp.getActiveSpreadsheet();
//現在アクティブなスプレッドシートのシートをコピーして、それを変数duplicateSheetに代入
const duplicateSheet = mySS.duplicateActiveSheet();
// コピーしたシート名をSheet_シートIDに変更
duplicateSheet.setName("Sheet_" + duplicateSheet.getSheetId());
// コピーしたあたらっシシートの列幅調整と2行の固定行の指定
duplicateSheet.autoResizeColumns(1, 5);
duplicateSheet.setFrozenRows(2);
// F列をC列に移動
var myRange = duplicateSheet.getRange("F2:F");
myRange.moveTo(duplicateSheet.getRange("C2"));
// 列C内のアボガドの値段による並べ替え
myRange = duplicateSheet.getRange("A3:D55");
myRange.sort(3);
}
結果は次の通りです。


おわりに
如何だったでしょうか?
スプレッドシートサービスとは?、スプレッドシートの読み込み及びGASの起動、学習するためのスプレッドシートファイルのコピーの作成、GASの起動、スプレッドシート(Spreadsheet)のメソッド、アクティブなスプレッドシートの名前変更、アクティブシートのコピー、シート(Sheet)メソッド、シート名の変更、シートの列幅の変更、Rangeオブジェクトのメソッド、範囲移動、範囲並べ替えなどについて解説してきました。
この記事が少しでもあなたにとって役に立てればこれほど嬉しいことはありません。
以上です。




コメント