見出し画像

【GAS】Google Apps Script 活用事例 @nepia_infinityスニペット集

普段実務で、よく使っているコードを、いわゆるスニペットとしてまとめました。


ライブラリとして公開しました

スニペットをライブラリとして公開しました。

スクリプトID

18rg2maFYXNmPmB2R-8s3UuFG850j5OLw4WBvcOrghzRMlfVbQWDgOVvZ

アクティベート方法

ライブラリを追加 プラスボタンをクリック
上述したスクリプトIDを入力してください

上述のスクリプトIDを入力してください。
青枠のIDについては、ライブラリを呼び出す際の名前になります。
例えば、nepia_infinity とした場合、下記のように記述すると関数を自由に使えるようになります。

function myFunction(){
  // ご自身のスプレッドシートのURLを指定してください
  const url   = 'https://docs.google.com/spreadsheets/d/********/edit#gid=****';
  const sheet = nepia_infinity.getSheetByUrl(url);
}

ライブラリで使用できる関数一覧

シートの取得

function myFunction(){
 const url       = '*******************';
 const sheet     = getSheetByUrl_(url); //シートオブジェクトを取得する
 const sheetName = getSheetByUrl_(url, 'sheetName'); //シート名を取得する
}


/**
 * SpreadsheetのURLからsheetオブジェクトを取得する。
 * シート名を取得したい場合は、2番目の引数に、'sheetName' と指定する。
 * 
 * @param  {string} sheetUrl - スプレッドシートのURL
 * @param  {string} string - 引数の省略可。'sheetName' と指定する
 * @return {SpreadsheetApp.Sheet|string} オブジェクトかシート名を返す。
 * 
 */
function getSheetByUrl(sheetUrl, string) {

  console.info(`getSheetByUrl() を実行中`);
  console.info(`01_spreadsheetに記載`);

  

  // findメソッドで、対象のsheetが見つからない場合の処理
  try{
       const spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
    const sheetId     = Number(sheetUrl.split('#gid=')[1]); //['https....', 'sheetId(typeof string)']
    const sheet       = spreadsheet.getSheets().find(sheet => sheetId === sheet.getSheetId());
    const sheetName   = sheet.getName();

    console.log(`sheetId:${sheetId}, シート名:${sheetName}`);
    (string === 'sheetName') ? console.warn(`型:${typeof sheetName}`) : console.log(`型:${typeof sheet}`);

    return (string === 'sheetName') ? sheetName : sheet

  }catch{
    console.warn(`エラーが発生しました。URLが正しくない可能性があります。`);
    return undefined
  }
}

getSheetByName() だとシート名が変わるとエラーが起きてしまいます。
上記のスクリプトでは、スプレッドシートのURLの文字列からシートを取得する事が出来ます。

getValues for

function getValues_(sheetName) {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadsheet.getSheetByName(sheetName);
  const values = sheet.getDataRange().getDisplayValues();

  console.log(values);

  values.forEach((row) => {
    if (row[0]) { // A列が空白でない場合のみ、処理を実行する
      console.log(row);
    }
  });
}

setValues

sheet.getRange(2, 1, newValues.length, newValues[0].length).setValues(newValues);

日付の2次元配列を作成

function getCal2023() {
 const startDate = new Date('2023/06/01');
 const endDate   = new Date('2023/12/31');

 const newValues = [];

  for(let d = startDate; d < endDate; d.setDate(d.getDate()+1)) {
    const day        = formatDay_(d.getDay());
    const stringDate = Utilities.formatDate(d, 'JST', 'yyyy/MM/dd');
    newValues.push([stringDate, day]);
  }

  console.log(newValues);
  return newValues
}



/**
 * 月~金までの曜日
 * 
 * @param  {number} tempNumber - d.getDay()、0-6までの数値
 * @return {string}
 */
function formatDay_(tempNumber) {
  const dayOfWeek = '日月火水木金土';
  return dayOfWeek.split('')[tempNumber];
}

formatDate

function myFunction122() {
  const date           = new Date('2022/04/09');
  const stringDate     = formatDate_(date, 'yyyy/MM/dd (E)');
  // const stringDate2 = formatDate_(date, 'yyyy/MM/dd');
}


/**
 * dateオブジェクトを、yyyy/MM/ddなどの指定した文字列で返す。
 * E - 曜日の指定があった際に wed → 水 のように変換する
 * 
 * @param  {date}    dateオブジェクト
 * @param  {sting}   'yyyy/MM/dd', 'yyyy/MM/dd HH:mm', 'yyyy/MM/dd (E)'
 * @return {string} (例)2022/04/06
 */
function formatDate_(date, format){
  const tempNumber = date.getDay(); 
  const formatDate = Utilities.formatDate(date, 'JST', format);

  if(formatDate.match(/[a-zA-Z]/)!== null){
    //文字列を配列化
    const dayOfWeek = '日月火水木金土';
    const daysArray = dayOfWeek.split('');
    const day       = daysArray[tempNumber];

    console.log(daysArray);
    console.log(`daysArray[${tempNumber}] ${day}曜日`);

    //2022/04/06 (wed) → 2022/04/06 (水) のように変換
    const marged = formatDate.replace(/[a-zA-Z]{3}/, `${day}`);

    console.log(`変換前の表記: ${formatDate}`);
    console.log(`変換後の表記: ${marged}`);
    return marged

  }else{
    //曜日の指定がない場合
    console.log(formatDate);
    return formatDate
  }
}

extractText

/**
 * 捜査対象のテキストから、文字列を消去して欲しい文字列を取得するための関数
 * 使用回数が多くなる傾向にあるので、意図的にconsole.infoを記載していない
 * 
 * @param  {string} string - 操作対象のテキスト
 * @param  {string} reg -  正規表現
 * @param  {Array.<string>} string - 残余引数で何個でも指定可、 置換対象の文字列
 * @return {string}
 * 
 */
function extractText(string, reg, ...params){

  const result   = string.match(reg);
  const replaced = result !== null ? params.reduce((accumulator, current) => accumulator.replace(current, ''), result[0])
    : (console.warn(`${reg}に一致しませんでした`), string);

  console.log(`オリジナルの文字列: ${string}`);
  console.log(`抽出された文字列:  ${replaced}`);

  return replaced

}

この関数を実行すると

function sampleText(){
  const sample ='面談_2025新卒_野比様';
  extractText_(sample, /面談_2025新卒_.*/, '面談_2025新卒_', '様');
}

replacedText

/**
 * テンプレート内の文字列をシートの値で流し込むスクリプト
 * 
 * @param  {string} template - 文字列
 * @param  {Array.<Array.<string>>} values - 2次元配列
 * @return {Array.<Array.<string>>} values - 2次元配列
 * 
 */
function replaceText_(template, values, ...placeholders) {
  const newValues = values.map((row) => {
    const replacedText = placeholders.reduce((accumulator, current, index) => accumulator.replace(current, row[index]), template);

    console.log(`${replacedText}`);
    return [replacedText];
  });

  return newValues;
}



function test_myFunction(){
  const template = '応募者名: {name}\nHRMOS URL: {hrmosUrl}\n\n';
  const values   = [
   ['佐藤', 'https://hrmos.co/selection/tabid=1111'], 
    ['鈴木', 'https://hrmos.co/selection/tabid=2222']
  ];

  const placeholders = ['{name}', '{hrmosUrl}'];
  replaceText_(template, values, ...placeholders);
}
  1. カレンダーの詳細欄のテンプレート

  2. ドキュメントで作成された原本

上記のようなテンプレートに、シートの値を挿入したいときによく使うスクリプトです。

getHeaderRow

/**
 * 空白行のあるシートから見出し行を見つけるスクリプト
 * 
 * @param  {Object} sheetオブジェクト
 * @return {number} 見出し行が存在する行を判定する
 */
function getHeaderRow_(sheet){
  const values = sheet.getDataRange().getDisplayValues();
  
  console.log(`関数名: getHeaderRow_(${sheet.getName()})を実行中`);

  let row = 1;
 
    //values[i]は1次元配列

  for(let i = 0; i < values.length; i++){
    if(values[i].indexOf('ID') !== -1 || values[i].indexOf('応募者名') !== -1){
      row += i;
      console.log(`ヘッダー行: ${row}`);
      return row
    }
  }//for
}

実務だと、空白行やセルの結合のオンパレードで苦労する事が多く、シートごとに異なるヘッダー行を判定する汎用的なスクリプトが書けたら便利だなと思って書きました。

replaceHeaderValues

/**
 * 2次元配列から見出し行の列数を連想配列として取得する
 * @param  {Array.<Array.<string|number>>} values - 2次元配列
 * @param  {number} number - 数字(index)
 * @param  {Object.<string>} original - 見出し行の名前を格納したオブジェクト
 * @return {Object.<number>} 
 */


function replaceHeaderValues_(values, rowIndex, targetColumn) {

  const header = values[rowIndex];
  console.log(header);

  console.log(`実行中の関数名: replaceHeaderValues_()`);
  console.log(`02_commonに記載`);
  
  // 2次元配列に変換する
  const entries = Object.entries(targetColumn);
  const column  = {};

  console.log(entries);

  for(const [key, value] of entries){
    column[key] = header.indexOf(value);

    // console.log(`key: ${key}`);
    // console.log(`value: ${value}`);
  }

  console.log(column);
  return column

}

列の挿入や削除対策のために見出し行から、列を特定します。これにより、不要なメンテを減らすことが出来ます。

翻訳ver

function generateHeaderIndex_() {
 const spreadsheet  = SpreadsheetApp.getActiveSpreadsheet();
 const sheet        = spreadsheet.getSheetByName('タスク一覧');
 const values       = sheet.getDataRange().getDisplayValues();

 //英語のドット記法にするために翻訳する。
 const headerRow    = values[0];
 const newElements  = headerRow.map(text => LanguageApp.translate(text, 'ja', 'en'));
 
 console.log(`翻訳前  : ${headerRow}`);
 console.log(`翻訳結果 : ${newElements}`);


 //オブジェクトにプロパティを追加する。
 let newObject = {};
 newElements.map(element => newObject[element] = newElements.indexOf(element));
 console.log(newObject);

 return newObject
}
​
スクリーンショット 2021-03-08 23.03.49

見出し行の単語が簡易(1単語、固有名詞なし)であれば、これでもいけそう....。例えば、もし見出し行の単語が、タスク名だった場合、タスクと名の2単語で成り立っているので、task nameとなってしまいます。しかも、残念な事にスペースが入ってしまいます。

ヘッダー行が英語の場合

function generateHeaderObject(){
  const sheet  = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  const values = sheet.getDataRange().getValues();
  const header = values.shift();//1次元配列

  const object = new Map();
  header.map((value, index) => object[value] = index);
  console.log(object);
}
ヘッダー行を特定できる 

日本語の場合、ChatGPTに依頼するためのプロンプト

「Googleスプレッドシートのヘッダーから各列のインデックスを取得し、それをオブジェクトのプロパティとして設定するJavaScriptのコードを書いてください。ヘッダーは以下の通りです:[“接頭語”, “予定名”, “予定日”, “開始時刻”, “終了時刻”, “出席者”, “イベント詳細”, “登録ステータス”, “詳細”]。」

このように具体的に依頼することで、私はあなたが望む出力を一度で提供することができます。他に何かお手伝いできることがありますか?

reduceColumn

/**
 * オブジェクトの中から引数に指定したkeyのみを取り出す
 * 
 * @param  {Array.<Object.<string|number>>} values - [{id: 'jp123', name: 'nobita'}]
 * @param  {string} theArgs - 取り出したいオブジェクトのkeyをいくつでも指定可
 * 
 */
function reduceObjectKeys(values, ...theArgs){

   console.log(`valuesから ${theArgs} の${theArgs.length}つを取り出す`);

  const reduced = values.reduce((prev, current) => {
    const obj = {};
    theArgs.map(arg => {
      obj[`${arg}`] = current[arg];
      // console.log(`obj[${arg}] = current[${arg}]`);

    });
    console.log(obj);
    
    prev.push(obj);
    return prev
    
  }, []);

  console.log(reduced);
  return reduced;

}

サンプルコード

function myFunction223(){
  const obj = [
    {
      id:         'JP12345',
      name:       '鳳凰院凶真',
      department: '秋葉原',
      mail:       'steinsgate@samaple',
      age:        '19'
    },
    {
      id:         'JP67890',
      name:       '牧瀬紅莉栖',
      department: 'NY',
      mail:       'steinsgate1@samaple',
      age:        '18'
    }
  ];

  reduceObjectKeys_(obj, 'id', 'name');

}

置換リストに沿って一括置換する

const value = 'abcabc';
const lists = [
  {target: /a/g, replaced: 'A'},
  {target: /b/g, replaced: 'B'}
];

const replaced = lists.reduce((acc, list) => acc.replace(list.target, list.replaced), value);

console.log(replaced);
const replaced = regexLists.reduce((accumulator, current) => accumulator.replace(...current), original);

似たような書き方のスクリプトとして、こんな感じで書く書くことが出来ます。

onOpen

function onOpen() {
 SpreadsheetApp.getUi()
   .createMenu('追加メニュー')
   .addItem('サブメニュー', 'myFunction1')
   .addItem('サブメニュー', 'myFunction2')
   .addToUi();
}

showPrompt

function searchAllSheet() {
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const ui          = SpreadsheetApp.getUi();
 const input       = showPrompt_(ui, '全シート検索', '検索したい語句を入力してください。');

 }


function showPrompt_(ui, title, sample) {
 const response = ui.prompt(title, sample, ui.ButtonSet.OK);
 const input    = response.getResponseText();

 console.log(input);

 switch (response.getSelectedButton()){
   case ui.Button.OK:
     console.log('%s と入力され、OKが押されました。',input);
     break;
   case ui.Button.CLOSE:
     console.log('閉じるボタンが押されました。');
     break;
   default:
     console.log('処理が中断されました。');
 }//switch
 
 return input

}
スクリーンショット 2021-02-27 20.59.27

showAlertBeforeExecution

function showAlertBeforeExecution() {
  const ui  = SpreadsheetApp.getUi();

  //状況に応じて変更する
  const template = {
    title: '●●テンプレート',
    event: '4/16 採用イベント' 
  };
  const folderId = '*********';

  const response = ui.alert(`原本やイベント名などに間違いはありませんか?\n\n
  原本名 : ${template.title}
  イベント: ${template.event}
  作成先 : ${folderId}`, ui.ButtonSet.YES_NO);
  
  switch (response){
    case ui.Button.YES:
      console.log('“はい” のボタンが押されました。');
      break;
    case ui.Button.NO:
      console.log('“いいえ” のボタンが押されました。');
      ui.alert('処理が中断されました。');
      break;
    default:
      console.log('処理が中断されました。');
  }//switch
}

テンプレートを取得して、人数分複製するみたいなスクリプトと一緒に使うと便利です。

createHtmlOutput

const file = '<p>虎杖悠仁</p><p>male</p>'
const ui   = SpreadsheetApp.getUi();
const html = HtmlService.createHtmlOutput(file)
.setWidth(450)
.setHeight(300);

ui.showModelessDialog(html, 'htmlを表示するよ');

スプレッドシート上で、簡単なhtmlファイルを表示することが出来ます。iframeを使うと、公開中の他のスプレッドシートを表示したりする事も可能です。スタイルもやろうと思えば指定出来ます。for文でシート内の情報を走査して出力結果を表示させたりするのに使ったら便利でした。

スクリーンショット 2021-02-27 18.20.21

Browser.msgBox

const result = Browser.msgBox("1. アイウエオ\\n2. カキクケコ,Browser.Buttons.OK_CANCEL);
if(result == 'ok'){

//具体的な処理内容

}

\\nで改行します。....そこまで使わないかな?

getActiveCell

/**
 * シートオブジェクトを引数にアクティブなセルの値、行、列などの情報を取得する
 * @param {SpreadsheetApp.Sheet} sheet - シートオブジェクト
 * 
 */
function getActiveCell_(sheet){
 const activeCell   = sheet.getActiveCell();
 const activeDetail = {
   row:    activeCell.getRow(),
   column: activeCell.getColumn(),
   value:  activeCell.getValue(),
   range:  activeCell.getA1Notation()
 }

 console.log(activeDetail);
 return activeDetail
}
スクリーンショット 2021-02-27 13.01.20

値、行、列、範囲などを返します。便利で重宝しています。if文での条件分岐の書きやすさ、ログの見やすさを加味して、現在の形に落ち着きました。

/**
 * 
 * @param {Object.< string| number >} e - イベントオブジェクト
 * 
 */
function onEdit(e) {
  const object = {
    sheetName:    e.source.getSheetName(),
    isBlank:      e.range.isBlank(),
    oldValue:     e.oldValue,
    currentValue: e.value,
    row:          e.range.getRow(),
    column:       e.range.getColumn(),
    range:        e.range.getA1Notation()
  }
  console.log(object);

}

generateArray

/**
 * 2次元配列を1次元配列に変換する
 * @param  {Array.<Array.<string|number>>} values - 2次元配列
 * @param  {number} number - 数字(index)
 * @return {Array.<string|number>} 1次元配列
 */
function generateArray_(values, column){
  return values.map(record => record[column]).filter(value => value);
}

2次元配列から、特定の1列を、1次元配列に変換します。これは、本当にとっても便利です。

convertToSingleColumn

/**
 * 2次元配列を、各元素を個別の配列要素とする新しい2次元配列に変換します。
 * @param {Array.<Array.<string|number>>} original - 変換対象の元の2次元配列。
 * @returns {Array.<Array.<string|number>>} - 各要素が個別の配列内に収められた新しい2次元配列。
 */
function convertToSingleColumn(original){

  const newValues = original.flat().reduce((accumulator, current) => {
    accumulator.push([current]);
    return accumulator;
  }, []);

  console.log(`変換後`);
  console.log(newValues);

  return newValues
}
こんな感じの2次元配列
縦一列の2次元配列に成形し直します

filter 特定の単語を含む2次元配列を生成

const newValues = values.filter(array => {
   if(array.indexOf('検索したい単語') !== -1){
     return array;
   }
});

console.log(newValues);

検索したい単語を含む1次元配列のみを残し、新しい2次元配列を作成します。

filter 配列に指定した全ての要素を含む行のみを取得する

const params          = ['合格', 'active'];
const regExpList = params.map(param => new RegExp(`${param}.*|.*${param}`));
const filtered     = values.filter(row => regExpList.every(reg => row.join(',').match(reg) !== null));
console.log(params);
console.log(filtered);

return filtered

上記の例では、2次元配列から合格かつactiveの条件を満たす行のみがtrueとなり新しい配列に加えられます。

filter 文字列が入力されている最終行を取得する

function myFunction() {
 const spreadsheet = SpreadsheetApp.openById('**************');
 const sheet       = spreadsheet.getSheetByName('RAW');
 const values      = sheet.getRange('A:A').getValues().filter(String);

 console.log(`最終行: ${values.length}`);
 console.log(values);
 
}

こちらは、ARRAYFORMULA関数などが入力されていて、最終行の取得が困難な場合に多用します。filterで文字列が入力されていない空白行を省きます。


ドキュメンテーションコメント 特に引数

{number}
{string}
{boolean}
{Date}

{Array.<number>} 数値型を値として持つ配列の例
{Array.<Array.<string>>} 2 次元配列

{Object.<string>} 文字列型を値として持つオブジェクト

Utilities.formatDate

const date       = new Date();
const formatDate = Utilities.formatDate(date,'JST', 'yyyy/MM/dd')

日付を変換する際の十八番的な処理
時間の場合は、'HH:mm' とすればOK

formatDate アロー関数版

const formatDate = (date, number, format) => {
   date.setDate(date.getDate() + number);
   return Utilities.formatDate(date, 'JST', format);
}

formatをyyyy/MM/ddだけではなく、yyyy_MMなど場面によって使い分けたい時に使用。基本は上記の処理

new Set 1次元配列の重複を削除

const array    = ['abc', 'abc'];
const newArray = Array.from(new Set(array));

console.log(newArray); //['abc']

2次元配列を、1次元配列にする際は、.flat()がおすすめ

removeDuplicates

//元データから重複を削除 配列操作をしない。
function removeDuplicates(sheetName, column) {
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const sheet       = spreadsheet.getSheetByName(sheetName);
 const range       = sheet.getRange('A2:Z');
 
 range.removeDuplicates([column]).activate();
 
}

シートから重複を削除します。破壊的メソッドのため、元データを編集してしまう事に注意が必要です。他のシートでも使いたいケースがあったため、別関数にして、シート名と列を引数にしてあげる事で、使い勝手がかなり良くなりました。

sort

const range = sheet.getRange('A2:Z');
range.sort([
  {column: 1, ascending: false}
]);

Twitter APIを使って調べた際、投稿日時の新しい順に整列する際に使用。A2にしているのは、見出し行を含まないようにするためです。

sort 関数として切り分ける場合

スクリーンショット 2021-03-07 8.31.18
function sortByColors() {
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const sheet       = spreadsheet.getSheetByName('タスク一覧 のコピー');
 const range       = sheet.getRange('A2:Z');

 range.sort([
   {column: 4, ascending: true},
   {column: 5, ascending: false}
 ]);
}

createTextFinder

/**
 * 検索ワード、行、列、範囲などの情報を連想配列で返す
 * 全てのシートが検索対象
 * 
 * @param  {string} sheetUrl - スプレッドシートのURL
 * @param  {string} query - スプレッドシートで検索したい単語
 * @param  {string} sheetName - 検索したいシートの名前 検索対象を絞りたい場合に使用
 * @return {Array.<Object.<srting | number>>} 
 */
function createTextFinder(sheetUrl, query, sheetName){

  const spreadsheet = SpreadsheetApp.openByUrl(sheetUrl);
  let finder;

  if(sheetName){
    // シート名が指定されている場合、指定したシートでテキスト検索を実行
    const sheet = spreadsheet.getSheetByName(sheetName);
    finder = sheet.createTextFinder(query).useRegularExpression(true);

  }else{
    // シート名が指定されていない場合、全てのシートでテキスト検索を実行
    finder = spreadsheet.createTextFinder(query).useRegularExpression(true);

  }

  const results  = finder.findAll();
  const newArray = results.map(result => ({
    query,
    sheetName: result.getSheet().getName(),
    row:       result.getRow(),
    column:    result.getColumn(),
    range:     result.getA1Notation(),
    value:     result.getValue()
  }));

  console.log(`検索語句: ${query} , 検索結果: ${newArray.length} 件`);
  console.log(newArray);

  return newArray;
}

検索キーワードがシートのどこに存在するのかを見つけるスクリプト

UrlFetchApp()

const targetUrl = '****************';
const response  = UrlFetchApp.fetch(targetUrl);
const html      = response.getContentText();

console.log(html);

ここからmatchなどを使って、情報を取り出します。gasでウェブスクレイピングや、拡張子をコンバートする際に使用します。

getEvents 曜日や出席者も取得するパターン

function getCalEvent_(targetTitle) {
 const startDate = new Date('2021/04/27');
 const endDate   = new Date('2022/05/20');

 const cal    = CalendarApp.getCalendarById('****************');
 const events = cal.getEvents(startDate, endDate);
 
 //日付
 const today    = Utilities.formatDate(startDate, 'JST', 'yyyy/MM/dd');
 const tomorrow = Utilities.formatDate(endDate, 'JST', 'yyyy/MM/dd');
 
 console.log(`取得開始日 ${today}、取得終了日 ${tomorrow}`);
 
 let newValues = [];
 let count     = 0;

 for(const event of events){
   
   info = {
     title:  event.getTitle(),
     day:    dayOfTheWeek_(event.getStartTime().getDay()),
     date:   Utilities.formatDate(event.getStartTime(), 'JST', 'MM月dd日'),
     start:  Utilities.formatDate(event.getStartTime(), 'JST', 'HH:mm'),
     end:    Utilities.formatDate(event.getEndTime(), 'JST', 'HH:mm'),
     guests: guestList_(event.getGuestList())
   }
  
  // ['イベントタイトル', '2021/05/12(水)', '11:00〜12:00', '******@gmail.com,******@gmail.com']
  const stringDate = `${info.date}${info.day})`;
  const period     = `${info.start}${info.end}`;
   if(info.title.includes(targetTitle)){
     newValues.push([info.title, stringDate, period, info.guests]);
     count += 1;
   }
 }//for

 console.log(`カレンダー登録件数 ${count} 件`);
 console.log(newValues);

 return newValues
 
}//end

補足: オブジェクトを配列に変換

上記のようなオブジェクトで取得したデータをスプレッドシートなどに貼り付けるために、配列に変換するスクリプト

//上記の例だと、keysとして下記の1次元配列を取得
//['title', 'date', 'start', 'end', 'description']

const keys   = Object.keys(events[0]);
const values = events.map(event => keys.map(key => event[key]));

console.log(values);
 
スクリーンショット 2021-02-27 15.08.48

連想配列の全ての要素に1を足す

/**
* 連想配列の全ての要素に1を足す。
* 
* values[0].indexOf('名前'); //expected output: 2
* 上記のように見出し行から列の位置を特定するスクリプト
* getRangeでも使いたい場合に使用
* 
*/

function modifyObject_(original) {
 
 const object = Object.keys(original).reduce(
   (after, key) => ({...after, [key]: original[key] += 1}),{}
 );
 console.log(object);
 return object
}

こちらは配列のindexを、getRangeで利用する時に、1ずれてしまう問題を回避するための関数です。

const original     = {id: 0, name: 1, address:2};
const copiedObject = Object.assign({}, original);
const column       = modifyObject_(copiedObject);

selectColumns

/**
 * getDataRange()などで取得した2次元配列から必要な列だけを抽出し、新しい2次元配列を作成する
 * 
 * @param  {Array.<Array.<string|number>>} values - 元の2次元配列
 * @param  {Object.<number>} column - 見出し行のオブジェクト (例) {id: 0, name: 1, university: 3}
 * @param  {Array.<string>} queries - 2次元配列から情報を取捨選択するためのキーワード、残余引数なので、いくつでも指定可
 * @return {Array.<Array.<string|number>>} 新しい配列
 *
 */
function selectColumns(values, column, ...queries) {

  console.info(`selectColumns()を実行中`);
  console.info(`01_spreadsheetに記載`);
  
  //{id: 0, name: 1, university: 3} -> [0, 1, 3]
  const columnsToSelect = Object.values(column);
  console.log(columnsToSelect);

  // 指定された列のインデックスを抽出し、新しい2次元配列を作成する
  const newValues = values.map(row => columnsToSelect.map(index => row[index]));

  // 指定したすべての単語に合致する行のみを残す
  const filtered = newValues.filter(row => {
    return queries.every(query => row.join(',').includes(query));
  });

  console.log(filtered);
  return filtered;
}

2次元配列から、必要な列のみ抽出するスクリプトです。QUERY関数のSELECTに似ています。

スプレッドシートの2次元配列をオブジェクトに変換する

function createObjects() {
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const sheet       = spreadsheet.getSheetByName('ハッシュタグ');
 const values      = sheet.getDataRange().getValues();
 const headers     = values.shift();

 console.log(headers);

 const objects = [];
 let count     = 1;

 for (const row of values) {

   count += 1;
   const object = {};
   
   for (const [index, value] of headers.entries()) {
     //ヘッダー、見出し行の構成要素が、keyになる
     object[value] = row[index];

   }
   objects.push(object);
 }

 console.log(objects);
 console.log(objects[0]['ハッシュタグ']);

 return objects;
 
}
スクリーンショット 2021-03-07 9.53.48
スクリーンショット 2021-03-07 10.02.30

registerEvents カレンダーに予定を登録

function registerEvents() {
 const calendar    = CalendarApp.getDefaultCalendar();
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const sheet       = spreadsheet.getSheetByName('スケジュール登録シート');
 const values      = sheet.getDataRange().getValues();


 //見出し行から列を特定する。シートに列の挿入などがあっても対応するための記述
 const headerRow = values[0];
 const column    = {
   id:     headerRow.indexOf('ID'),
   title:  headerRow.indexOf('イベント名'),
   date:   headerRow.indexOf('開始日'),
   start:  headerRow.indexOf('開始時刻'),
   end:    headerRow.indexOf('終了時刻'),
   status: headerRow.indexOf('登録ステータス'),
 }   


 //見出し行を除外する。
 for(let i = 1; i < values.length; i++){
   //ステータスが登録済だった場合はスキップ
   if(values[i][column.status] === '登録済'){continue}

   //開始時刻
   const startTime = new Date(values[i][column.date]);
   startTime.setHours(values[i][column.start].getHours());
   startTime.setMinutes(values[i][column.start].getMinutes());

   //終了時刻
   const endTime = new Date(values[i][column.date]);
   endTime.setHours(values[i][column.end].getHours());
   endTime.setMinutes(values[i][column.end].getMinutes());

   const event   = calendar.createEvent(values[i][column.title], startTime, endTime);

   //イベントIDを書き込む getRange()用に +1をしている。
   const row          = i + 1;
   const idColumn     = column.id + 1;
   const statusColumn = column.status + 1;

   //イベントID・登録ステータスを書き込む
   sheet.getRange(row, idColumn).setValue(event.getId());
   sheet.getRange(row, statusColumn).setValue('登録済');
 }
}

イベントIDは、カレンダーの予定をあとで編集する場合に使います。

const options = {
 location:    '東京都港区青山',
 guests:      '****@sample.jp, *****@sample1.jp',
 description: 'イベント詳細説明欄',
 sendInvites: false
}

calendar.createEvent(calTitle, startTime, endTime, options);

上記の部分の最後の引数に、optionを指定する事が出来ます。参加者や、招待の有無などを指定することができます。

特定のイベントを削除する

function deleteEvent() {
 const calendar = CalendarApp.getDefaultCalendar();
 const date     = new Date(); 
 const events   = calendar.getEventsForDay(date);

 for (const event of events) {
   //イベントタイトルに仮が含まれていれば、削除
   const eventTitle = event.getTitle();
   if(eventTitle.indexOf('仮') !== -1){
     event.deleteEvent();
   }//if
 }//for
}//end

出席者を取得する

function guestList_(guests){
 let array = [];
 for(const guest of guests){
   const accountId = guest.getEmail();
   array.push(accountId);

 }
 //配列を文字列化する
 const guestsList = array.join();
 return guestsList
}

Drive フォルダ内に存在するファイルを取得

function getDriveFiles(){
 const folder = DriveApp.getFolderById('*************');
 const files  = folder.getFiles();

 console.log(folder.getName());
 console.log(files);

 while (files.hasNext()) {
   const file     = files.next();
   const fileName = file.getName();

   console.log(fileName);
 }
}

フォルダ内の特定ファイルを移動させる

こちらのスクリプトでは、名前にコピーが含まれているファイルだけを移動させる。

function getDriveFiles(){
 const folder = DriveApp.getFolderById('****************'); //元のフォルダ
 const files  = folder.getFiles();

 console.log(folder.getName());

 const destination = DriveApp.getFolderById('***********'); //移動先のフォルダ

 let count = 0;
 while (files.hasNext()) {
   const file     = files.next();
   const fileName = file.getName();

   if(fileName.includes('コピー')){
     console.log(fileName);
     const replacedName = fileName.replace(' のコピー', '');

     //replaceと移動
     file
     .setName(replacedName)
     .moveTo(destination);

     count += 1;
   }
 }
 console.log(`${count} 件`);
}

シート上の情報  = フォルダ名になるようにフォルダを作成する

function createFolders() {
 const folder = DriveApp.getFolderById('****************');
 console.log(folder.getName());

 const nameArray = ['folderA', 'folderB', 'folderC']

 for (let i = 0; i < nameArray.length; i++){
   const fileName = nameArray[i];
   folder.createFolder(fileName);
 }
}

makeCopy

スプレッドシートの情報をドキュメントへ流し込みたい場合に使用します。

Switch test 正規表現が使える

function getTargetText_(plainText){
 let string = '';

 switch (true) {
   case /.*検索したい語句.*/.test(plainText):
     //処理を書く
     console.log(string)
     break;
   default:
     console.log('どのパターンにも該当しませんでした。')
     break;
 }//switch

 return string
}//end

textFinder

//全角を一括で、半角スペースに変換
const textFinder  = sheet.createTextFinder(' ');
textFinder.replaceAllWith(' ');

Document 本文を取得

function getDocText(){
 const url      = '***************';
 const document = DocumentApp.openByUrl(url);
 const body     = document.getBody();
 const text     = body.getText();
 
 console.log(text);
 
}

ドキュメントに、文章の下書きなどを保存して置いて、スプレッドシート 側で呼び出したりするケースが多いので、openByUrl()にしています。

Slides ページ数と本文を取得

function getSlidesContents(){

 const presentation = SlidesApp.getActivePresentation();  
 const slides       = presentation.getSlides();

 let page = 1;

 for(const slide of slides){
   const shapes = slide.getShapes();

   for(const shape of shapes){
     const info = {
       text :      shape.getText().asString(),
       objectId:   shape.getObjectId()
     }
     console.log('page : ', page, ' text : ', info.text);
   }
   page += 1;
 }
}

Slides mapを使用した短縮形

function getSlidesContents(){
 const presentation = SlidesApp.getActivePresentation();  
 const slides   = presentation.getSlides();
 const contents = slides.map((slide, index) => slide.getShapes().map(shape => ({
       text :    shape.getText().asString(),
       objectId: shape.getObjectId(),
       page:     index + 1
     })
   )//map shapes
 );//map slides

 console.log(contents[0]); //[{},{}]
 console.log(contents[0][0].text); //text

}
スクリーンショット 2021-02-28 6.41.55

getGmail Gmailのスレッドを検索して内容を取得

function getGmail_() {
 
 const query   = '【メルカリ】保存した検索条件への新着';
 const threads = GmailApp.search(query, 0, 7); //最新の受信日から、7スレッドまでを検索
 
 console.log(threads);
 

 let newValues = [];

 //スレッドを取得する
 for (const thread of threads){
   const link     = thread.getPermalink();
   const messages = thread.getMessages();

   //一つ一つのスレッドにある各メッセージを取得する。
   for(const message of messages){

     const info = {
       date:    Utilities.formatDate(message.getDate(), 'JST', 'yyyy/MM/dd HH:mm'),
       from:    message.getFrom(),
       subject: message.getSubject(),
       text:    message.getPlainBody(),
       html:    message.getBody(),
     }

     newValues.push([info.date, info.from, info.subject, info.text, link]);

   }//for
 }//for

 console.log(newValues);
 return newValues

}//end
スクリーンショット 2021-02-27 19.32.22

getGmail mapを使用した短縮形

スレッドに1つ以上のメッセージがあると、上手く拾えないかもしれません。

function getGmail() {
 const query    = '【メルカリ】保存した検索条件への新着';
 const threads  = GmailApp.search(query, 0, 7); //最新の受信日から、7スレッドまでを検索
 const messages = threads.map(thread => thread.getMessages().map(message => ({
       date:    Utilities.formatDate(message.getDate(), 'JST', 'yyyy/MM/dd HH:mm'),
       from:    message.getFrom(),
       subject: message.getSubject(),
       text:    message.getPlainBody(),
       link:    thread.getPermalink(),
       html:    message.getBody()
     })
   ) //map messages
 ); //map threads

 console.log(messages);

}//end


この記事が気に入ったらサポートをしてみませんか?