見出し画像

【GAS】Google Apps Script 活用事例  ドキュメントの置換を一括で行うスクリプト

ドキュメントを一括で置換したい

採用事務だと、面接などの希望日程をフリーフォーマットでもらう事が多く、中にはひどく見辛いものもあって、ペーストした文章を一括で変換したいなぁと思って、スクリプトを作成しました。

スクリプト全文

function onOpen() {
 SpreadsheetApp.getUi()
   .createMenu('追加メニュー')
   .addItem('文章を変換する', 'modifyStrings')
   .addToUi();
}

/**
 * 実行する関数
 * 
 */
function modifyStrings() {
  const document     = DocumentApp.getActiveDocument();
  const body         = document.getBody();
  const originalText = body.getText();
  console.log(originalText);

  let replaced = replacedText_(originalText);
  replaced = replaced.replace(/undefined/g, '');
  body.setText(replaced);

}

/**
* 文章を2次元配列内の置換リストに基づいて一括で変換する
*
* @param  {string} string - 置換前の文字列
* @return {string} string - 置換後の文字列
*/
function replacedText_(string){
  // 1次元配列の中身 [/置換対象の正規表現/g, '置換後の単語']
  const lists = [
    [/:/g,     ':'],
    [/スタート/g, ''],
    [/~/g, ' - '],
    [/~/g, ' - '],
    [/〜/g, ' - '], //同じに見えるけど違うっぽい
    [/時以降開始/g, ':00'],
    [/終了まで/g, ''],
    [/時終了/g, ':00'],
    [/終了/g, ''],
    [/(開始).*/g, ''],
    [/ (.*/g, ''],
    [/ また /g, ' or '],
    [/第.希望./g, ''],
    [/曜日/g, ' '],
    [/ /g, '\n'],
    [/時から/g, ':00 - '],
    [/時まで/g, ':00'],
    [/時/g, ':00'],
    [/時半/g, ':30'],
    [/ : /g, ':'],
    [/\(/g, ' ('],
    [/\)/g, ') '],
    [/(/g, ' ('],
    [/)/g, ') '],
    [/ /g, ' '],
    [/>/g, ' '],
    [/【/g, ' '],
    [/】/g, ' '],
  ];

  console.log(lists);

  // reduceの引数(accumulator, current, index, array)
  const replaced = lists.reduce((acc, list) => acc.replace(...list), string);
  console.warn(`変換後`);
  console.log(`${replaced}`);

  const refined = refineText_(replaced);
  return refined

}


function refineText_(original) {
  const regex = /\b(日|月|火|水|木|金|土)\b/;
  const match = original.match(regex);

  const targetArray = original.split('\n');
  console.log(targetArray);
  let newString = '';

  if (match) {

    //○月○日をyyyy/MM/ddに直す
    targetArray.map(string => newString += refineDateString_(string));
    console.log(newString);

    return newString

  }else {

    console.warn('m/DDなどのフォーマットかつ、文字列に曜日は含まれていません');
    // 日付を各文字列に書き足す
    targetArray.map(string => newString += appendDayOfWeek_(string));
    console.log(newString);
    
    return newString

  }
}

/**
 * 日付に曜日があるかどうかを判定してなければ曜日を追加する
 * 
 * @param {string} original - 文字列
 * 
 */
function appendDayOfWeek_(original){
  
  const regex = /^(\d{1,2}\/\d{1,2})/;
  const match = original.match(regex);

  if (match) {
    //12月や1月など年を跨ぐ日程調整では間違った結果が出力する可能性が高い
    const today = new Date();
    const year  = today.getFullYear();
    console.log(`年を取得: ${year}`);

    const dateString = match[1];
    const rest   = original.replace(dateString, '');
    const marged = `${year}/${dateString}`;

    console.log(`matchの結果: ${dateString}  型:${typeof dateString}`);
    console.log(`文字列を結合: ${marged}`);

    const date    = new Date(marged);
    let newString = formatDate_(date, 'yyyy/MM/dd (E)');
    newString += `${rest}\n`;

    console.log(newString);

    return newString

  }
}



/**
 * dateオブジェクトを、yyyy/MM/ddなどの指定した文字列で返す。
 * E - 曜日の指定があった際に wed → 水 のように変換する
 * 
 * @param  {date}    date - dateオブジェクト
 * @param  {sting}   format - '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
  }
}


/**
 * @param {string} original - 文字列
 * @return {string} yyyy/MM/dd(E)のフォーマットに修正した文字列
 */
function refineDateString_(original){
  const regex = /^(\d{1,2}月\d{1,2}日)/;
  const match = original.match(regex);
  console.log(match);

  if (match) {
    const replaced = match[0]
    .replace('月', '/')
    .replace('日', '');

    const rest = original
    .replace(match[0], '')
    .replace(/\(.*\)|(.*)/, ''); //半角と全角の括弧を消す

    const marged     = replaced + rest;
    const dateString = appendDayOfWeek_(marged); // yyyy/MM/dd(E)

    return dateString
  }
}

GAS単体だと、出来ることはこのくらいなんですが、listsの部分を動的に、例えば機械学習とかで実装出来たら、さらに汎用性が高くなりそうな気がしています。

実行前

木曜の誤変換も変換してくれた

実行後

見やすい

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