九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、この間 PhpSpreadsheetでExcelを操作する全26実例!という記事を公開しましたが、意外にもこの記事へのアクセスが多かったので「やっぱりPHPでExcelを操作する需要って多いんだな😊」と考えていました。
ちなみに、私はプログラム開発に都合がいいことが多いためメインのOSにはLinux
を使っています。そのため、Excel
はVirtualBox
内のWindows
で実行するようにしていますが、正直いちいち起動するのはめんどうだったりもします。
そこで重宝するのが「Google版Excel」という位置づけの「Google スプレッドシート」です。なぜならGoogleが開発しているだけあってブラウザ上で完結させることができるからです。(しかも、設定によってオフラインでの編集もできるようです)
そして、以前 Laravel で注文データをGoogleスプレッドシートに追加するという記事ではGoogle Sheet
のAPIについて一部を紹介しましたが、まだ他にもプログラムでスプレッドシート操作やデータ取得することができることがあるので、今回は全体的にGoogle Spreadsheet API
の使用法を紹介したいと思います。
ぜひ皆さんのお役に立てると嬉しいです😊✨
実行環境: PHP 7.2
Google APIの準備
Google Spreadsheet API
を使うには、Google API コンソールで有効にする必要があります。詳しい内容は Laravel で注文データをGoogleスプレッドシートに追加するの以下の項目を参照してください。
Google Spreadsheet APIの基本的な使い方
クライアントを作成(はじめに読んでおいてください)
Google Spreadsheet API
に限らずですが、PHPからGoogleのAPIへアクセスするには、まずGoogle_Client
というクラスのインスタンスを作り、このインスタンスをスプレッドシートAPIなど各種クラスに渡してデータの送受信をすることになります。
例えば以下の例は、Google スプレッドシート
とGoogle ドライブ
のAPIにアクセスができるようになるクライアントの作り方です。
$credentials_path = '(ダウンロードした認証用JSONファイルへのパス)'; $client = new \Google_Client(); $client->setScopes([ \Google_Service_Sheets::SPREADSHEETS, // スプレッドシート \Google_Service_Sheets::DRIVE, // ドライブ ]); $client->setAuthConfig($credentials_path);
ということで、ここからの説明で$client
と書いてある場合は、上記のインスタンスのことを指していると考えて読み進めてください。
新しいスプレッドシートを作成する
全く新しいスプレッドシートを作成するには、以下のようにcreate()
メソッドを使用します。
$spreadsheet_service = new \Google_Service_Sheets($client); $requestBody = new \Google_Service_Sheets_Spreadsheet([ 'properties' => [ 'title' => '新しいスプレッドシート' ] ]); $response = $spreadsheet_service->spreadsheets->create($requestBody); $spreadsheet_id = $response->spreadsheetId; // 作成されたスプレッドシートのID
【注意】
ただし、この例でスプレッドシートを作成しても、あなたのGoogle スプレッドシートには表示はされません。
なぜなら、スプレッドシートを作成したのはAPIのダミーユーザーだからです。(ダウンロードしたJSONファイル内に書かれているメールアドレスがこのユーザーに当たります)
そのため、もしあなたのスプレッドシートからでもアクセスできるようにしたい場合は、Google Drive API
で権限を与える必要があります。
Laravel で注文データをGoogleスプレッドシートに追加する を参考にしてGoogle Drive API
を有効にし、さきほどの例のように「\Google_Service_Sheets::DRIVE」が追加されていることを確認して、以下のコードを追加してください。
$spreadsheet_id = $response->spreadsheetId; // 作成されたスプレッドシートのID // (さっきの続き) $email = '(権限を与えたいGoogleユーザーのメールアドレス)'; $drive_permission = new Google_Service_Drive_Permission(); $drive_permission->setEmailAddress($email); $drive_permission->setType('user'); $drive_permission->setRole('owner'); $drive_service = new \Google_Service_Drive($client); $drive_service->permissions->create($spreadsheet_id, $drive_permission, [ 'transferOwnership' => 'true' // コピー等の権限あり ]);
これで、あなたのアカウントから作成したスプレッドシートにアクセスできるようになりますので、以下のようにブラウザ上からでも確認することができるはずです。
スプレッドシートからデータを取得する
ひとつの範囲からだけ取得
続いては、スプレッドシートからデータを取得する方法です。例えば、以下のようになっているスプレッドシートからデータを取得してみましょう。
$spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $range = 'Sheet1!A1:C5'; // 取得する範囲 $response = $spreadsheet_service->spreadsheets_values->get($spreadsheet_id, $range); $values = $response->getValues(); print_r($values);
取得できるデータは以下のようにの配列になります。
Array ( [0] => Array ( [0] => A1 [1] => B1 [2] => C1 ) [1] => Array ( [0] => A2 [1] => B2 [2] => C2 ) [2] => Array ( [0] => A3 [1] => B3 [2] => C3 ) [3] => Array ( [0] => A4 [1] => B4 [2] => C4 ) [4] => Array ( [0] => A5 [1] => B5 [2] => C5 ) )
※ スプレッドシートのIDの取得は、作成したスプレッドシートのIDを取得するを参考にしてみてください。
$range
の書式は次のようになっています。
(シートの名前)!(セルの範囲)
シートの名前は、ブラウザでスプレッドシートにアクセスし、画面左下に表示されています。
そのためもしシートの名前が「売上管理」だった場合の範囲指定は以下のようになります。
$range = '売上管理!A1:C5';
なお、先ほどの例では、行(ぎょう。横方向)を基準とした配列で取得しましたが、これを列(れつ。縦方向)を基準にしたい場合は以下のようにオプションを指定するといいでしょう。
$spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $range = 'Sheet1!A1:C5'; $options = [ 'majorDimension' => 'COLUMNS' ]; $response = $spreadsheet_service->spreadsheets_values->get($spreadsheet_id, $range, $options); $values = $response->getValues(); print_r($values);
これを実行すると以下のように(5×3)の配列になります。(先ほどは3×5)
Array ( [0] => Array ( [0] => A1 [1] => A2 [2] => A3 [3] => A4 [4] => A5 ) [1] => Array ( [0] => B1 [1] => B2 [2] => B3 [3] => B4 [4] => B5 ) [2] => Array ( [0] => C1 [1] => C2 [2] => C3 [3] => C4 [4] => C5 ) )
複数の範囲から取得
一気に複数の範囲からデータを取得する場合です。
$spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $response = $spreadsheet_service->spreadsheets_values->batchGet( $spreadsheet_id, [ 'ranges' => [ 'Sheet1!A1:C5', 'Sheet2!A1:C3', // いくつでも追加できます ] ] ); $value_ranges = $response->getValueRanges(); foreach ($value_ranges as $value_range) { print_r($value_range->getValues()); }
スプレッドシートのデータを更新する
ひとつの範囲のみデータ更新する
try { $values = [ [100, 1000, '=(A9+B9)', 'テスト文字列', '2019-01-11'], [200, 2000, '=(A10+B10)', 'テスト文字列', '2019-01-12'], [300, 3000, '=(A11+B11)', 'テスト文字列', '2019-01-13'], ]; $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $range = 'Sheet1!A9:E11'; $body = new \Google_Service_Sheets_ValueRange([ 'values' => $values ]); $body->setValues($values); $params = ['valueInputOption' => 'USER_ENTERED']; // データの入力方法 ※ $result = $spreadsheet_service->spreadsheets_values->update( $spreadsheet_id, $range, $body, $params ); echo $updated_cell_count = $result->getUpdatedCells(); } catch (\Exception $e) { // エラー処理 }
※ データの入力方法は以下の2つです。
USER_ENTERED
ブラウザでデータを入力するのと同じ。
つまり、計算式や日付は自動的に解釈されることになります。
RAW
上記の解釈をしない、つまりそのままの状態で入力します。
複数の範囲をデータ更新する
一気に複数のデータを更新する場合です。
try { $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $data = []; $data[] = new \Google_Service_Sheets_ValueRange([ 'range' => 'Sheet1!A9:E9', 'values' => [ [100, 1000, '=(A9+B9)', 'テスト文字列', '2019-01-11'] ] ]); $data[] = new \Google_Service_Sheets_ValueRange([ 'range' => 'Sheet1!A10:E10', 'values' => [ [200, 2000, '=(A9+B9)', 'テスト文字列', '2019-01-12'] ] ]); $data[] = new \Google_Service_Sheets_ValueRange([ 'range' => 'Sheet1!A11:E11', 'values' => [[ 300, 3000, '=(A9+B9)', 'テスト文字列', '2019-01-13' ]] ]); $body = new \Google_Service_Sheets_BatchUpdateValuesRequest([ 'valueInputOption' => 'USER_ENTERED', // 入力方法 ※ 'data' => $data ]); $result = $spreadsheet_service->spreadsheets_values->batchUpdate($spreadsheet_id, $body); echo $updated_cell_count = $result->getTotalUpdatedCells(); } catch (\Exception $e) { // エラー処理 }
※ 入力方法は、ひとつの範囲のみデータ更新するを参照してください。
データを最終行から追加する
ある場所を基準としてそこから順にデータを追加する場合です。
つまり、例えば基準場所を「A9」に指定したけれどすでにデータが存在しているような場合を見てください。
この場合、以下のようにそれ以降の場所からデータ追加されることになります。
try { $values = [ [100, 1000, 10000], [200, 2000, 10000], [300, 3000, 10000], ]; $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $range = 'Sheet1!A9'; $body = new \Google_Service_Sheets_ValueRange([ 'values' => $values ]); $params = ['valueInputOption' => 'USER_ENTERED']; // 入力方法 ※ $result = $spreadsheet_service->spreadsheets_values->append($spreadsheet_id, $range, $body, $params); echo $updated_cell_count = $result->getUpdates()->getUpdatedCells(); } catch (\Exception $e) { // エラー処理 }
※ 入力方法は、ひとつの範囲のみデータ更新するを参照してください。
各シートを操作する方法
新しい「シート」をスプレッドシートに追加する
つまり、以下のように新しいシートを追加したい場合です。
try { $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $body = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ 'requests' => [ 'addSheet' => [ 'properties' => [ 'title' => '新しいシート' ] ] ] ]); $response = $spreadsheet_service->spreadsheets->batchUpdate($spreadsheet_id, $body); $new_sheet_id = $response->getReplies()[0] ->getAddSheet() ->getProperties() ->sheetId; echo($new_sheet_id); } catch (\Exception $e) { // エラー処理 }
シートの内容をクリアする
例えば、ある特定のシートに保存されている全データをクリアしたい場合です。
try { $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $body = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ 'requests' => [ 'updateCells' => [ 'range' => [ 'sheetId' => '(シートのID ※)' ], 'fields' => 'userEnteredValue,userEnteredFormat' // データ&セルの装飾をクリア ] ] ]); $spreadsheet_service->spreadsheets->batchUpdate($spreadsheet_id, $body); } catch (\Exception $e) { // エラー処理 }
※ シートのIDは、シートの名前ではなくIDです。シートIDを取得する方法は、シートの情報を取得するを参照してください。
シートの情報を取得する
例えば、以下のようなシートの名前やIDを取得したい場合です。
$spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $response = $spreadsheet_service->spreadsheets->get($spreadsheet_id); $sheets = $response->getSheets(); foreach ($sheets as $sheet) { $properties = $sheet->getProperties(); $sheet_id = $properties->getSheetId(); // シートID $sheet_title = $properties->getTitle(); // シートの名前 $sheet_index = $properties->getIndex(); // シートのインデックス(0, 1, 2...) }
シートを別のスプレッドシートにコピーする
例えば、「スプレッドシートA・シート1」を「スプレッドシートB」にコピーして追加する場合です。
$spreadsheet_service = new \Google_Service_Sheets($client); $original_spreadsheet_id = '(コピー元のスプレッドシートID)'; $original_sheet_id = '(コピー元のシートID)'; $new_spreadsheet_id = '(コピー先のスプレッドシートID)'; $new_spreadsheet = new \Google_Service_Sheets_CopySheetToAnotherSpreadsheetRequest(); $new_spreadsheet->setDestinationSpreadsheetId($new_spreadsheet_id); $response = $spreadsheet_service->spreadsheets_sheets ->copyTo( $original_spreadsheet_id, $original_sheet_id, $new_spreadsheet ); echo $new_sheet_id = $response->getSheetId(); // 作成されたシートのID
※ ちなみに、コピーを実行するにはサービスアカウント(APIが使うダミーのユーザー)がコピーの権限を持っている必要があります。そのため、全てプログラム上で実行する場合はtransferOwnership
をtrue
にしてスプレッドシートを作成するといいでしょう。
コピーが成功すると以下のようになります。
シートを削除する
特定のシートを削除する場合です。
try { $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; $sheet_id = '(削除するシートのID)'; $body = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ 'requests' => [ 'deleteSheet' => [ 'sheetId' => $sheet_id ] ] ]); $response = $spreadsheet_service->spreadsheets->batchUpdate($spreadsheet_id, $body); } catch (\Exception $e) { // エラー処理 }
セルを装飾する
セルを装飾する基本
Google Spreadsheet API
ではセルの装飾はセル内のデータ更新と同じくbatchUpdate()
を使って行います。つまり、リクエストする内容を変更するだけで背景色やテキストの色、枠線などを変更することができるというわけです。
以下は、その基本となるコードです。(※ 以降の説明では$request_data
の部分のみを紹介します)
try { $spreadsheet_service = new \Google_Service_Sheets($client); $spreadsheet_id = '(スプレッドシートのID)'; // リクエストデータ $request_data = [ // 各種この部分を変更することで背景色や枠線などを変更できます ]; $requests = [new \Google_Service_Sheets_Request($request_data)]; $batchUpdateRequest = new \Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ 'requests' => $requests ]); $response = $spreadsheet_service->spreadsheets->batchUpdate($spreadsheet_id, $batchUpdateRequest); print_r($response->getReplies()); } catch (\Exception $e) { // エラー処理 }
背景色をつける
例えば、ある範囲の背景色をピンクに変更する場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(backgroundColor)', 'range' => [ 'sheetId' => '(シートのID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 10, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 5, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'backgroundColor' => [ // 色はRGB形式 'red' => 234/255, 'green' => 143/255, 'blue' => 143/255 ] ], ], ], ];
テキストの色を変える
例えば、ある範囲のテキスト色を赤に変更する場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートのID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 10, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 5, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'foregroundColor' => [ // 色はRGB形式 'red' => 200/255, 'green' => 10/255, 'blue' => 25/255 ] ] ], ], ], ];
テキストの右寄せ、中央寄せ、左寄せを指定する
例えば以下のように表示テキストを「左」「中央」「右」に寄せる場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(horizontalAlignment)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'horizontalAlignment' => 'CENTER' // 位置のパラメータ ※ ], ], ], ];
位置のパラメータは以下のとおりです。
- LEFT ・・・ 左寄せ
- CENTER ・・・ 中央寄せ
- RIGHT ・・・ 右寄せ
テキストを太字にする
以下のようにテキストを太字にする場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'bold' => true // 太字が有効 ] ], ], ], ];
フォントサイズを変更する
以下のようにフォントサイズを変更する場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'fontSize' => 30 // フォントサイズ ] ], ], ], ];
フォントを指定
以下のようにフォントのタイプを変更する場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'fontFamily' => 'Times New Roman' // フォント名 ] ], ], ], ];
テキストを斜めにする
以下のようにテキストを斜め(イタリック)にする場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'italic' => true // 斜め文字を有効 ] ], ], ], ];
テキストに下線をつける
セルではなく、テキストに下線をつける場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'underline' => true // 下線を有効 ] ], ], ], ];
テキストに打ち消し線をつける
以下のようにテキストに打ち消し線つける場合です。
$request_data = [ 'repeatCell' => [ 'fields' => 'userEnteredFormat(textFormat)', 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 1, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 1, // 列の終了位置 ], 'cell' => [ 'userEnteredFormat' => [ 'textFormat' => [ 'strikethrough' => true // 打ち消し線を有効 ] ], ], ], ];
枠線をつける
セルに枠線をつける場合です。
$request_data = [ 'updateBorders' => [ 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 1, // 行の開始位置 'endRowIndex' => 3, // 行の終了位置 'startColumnIndex' => 1, // 列の開始位置 'endColumnIndex' => 3, // 列の終了位置 ], 'top' => [ 'style' => 'SOLID', // 通常の線 'width' => 1, 'color' => ['red' => 0.3] ], 'bottom' => [ 'style' => 'DOTTED', // ドット線 'width' => 1, 'color' => ['red' => 0.5] ], 'right' => [ 'style' => 'DASHED', // ダッシュ線 'width' => 1, 'color' => ['red' => 0.7] ], 'left' => [ 'style' => 'DOUBLE', // 二重線 'width' => 1, 'color' => ['red' => 1.0] ] ], ];
枠線の種類は以下の6つです。
- DOTTED ・・・ ドット線
- DASHED ・・・ ダッシュ線
- SOLID ・・・ 通常の線
- SOLID_MEDIUM ・・・ 通常の線(少し太め)
- SOLID_THICK ・・・ 通常の先(太め)
- DOUBLE ・・・ 二重線
セルを結合する
セルを結合したい場合です。
$request_data = [ 'mergeCells' => [ 'range' => [ 'sheetId' => '(シートID)', 'startRowIndex' => 0, // 行の開始位置 'endRowIndex' => 3, // 行の終了位置 'startColumnIndex' => 0, // 列の開始位置 'endColumnIndex' => 3, // 列の終了位置 ], 'mergeType' => 'MERGE_ALL' // 結合する形式 ※ ], ];
結合する形式は以下の3つです。
MERGE_ALL
範囲すべてのセルを結合します。
MERGE_COLUMNS
セルを縦方向に結合します。
MERGE_ROWS
セルを横方向に結合します。
その他
スプレッドシートのタイトルを変更する
スプレッドシート本体のタイトルを変更する場合です。
$request_data = [ 'updateSpreadsheetProperties' => [ 'properties' => [ 'title' => '変更されたスプレッドシートのタイトル' ], 'fields' => 'title' ], ];
※ 実行方法はセルを装飾する基本をご覧ください。
シートのタイトルを変更する
シートのタイトルを変更する方法です。
$request_data = [ 'updateSheetProperties' => [ 'properties' => [ 'sheetId' => '(シートID)', 'title' => '変更されたシートのタイトル' ], 'fields' => 'title' ], ];
※ 実行方法はセルを装飾する基本をご覧ください。
おわりに
ということで今回はGoogle Spreadsheet API
を使ってスプレッドシートを操作する方法を紹介しました。
今回APIを使ってみて感じたことは、ほぼブラウザでできることがPHPのみならず各言語で操作可能なので、MicrosoftのExcelとはまた違った使い方が期待できるんじゃないかと感じました。(しかも、ブラウザで使えるのでOSがWindowsであろうが、Linuxであろうが関係ないですし、なんだったらスマホ用のアプリもありますしね😊✨)
ただ、Google はこういった保存データを利用して個人的な趣味嗜好を判別し広告表示していると言われているので、そこをどう感じるかという話はあるかと思います。
ぜひ皆さんもこの記事を使っていろいろと試してみてくださいね。
ではでは〜!
【追記:2020.5.25】
匿名ユーザー様から「v4ではなくv3ではないでしょうか」とご指摘をいただきました。
皆様、いつもありがとうございます😊✨
早速当時インストールしたパッケージを確認してみたのですが、結果として「Service definition for Sheets (v4)」と書いてあったため、現時点では v4 ではないかと考えております。
ただ、まだあやふやな点もありますので、もしどなたかこの件に関して情報がありましたらぜひ教えていただけますと嬉しいです。
どうぞよろしくお願いいたします。m_ _m(時間が空いてしまうと、当時のことがトコロテン方式で抜け落ちててしまうんですよね・・・😂)