見出し画像

【GAS】Google Apps Script 活用事例 全角を半角へ一括で書き換えるスクリプト

最近、GASを書いていて、複数の置換を一括で出来ないかなと思う場面に遭遇しました。etauさんが前にreduceを使って書いていたような.....朧げな記憶を辿って、探し当てたのが下記のエントリーです。

ざっくり言うと、置換対象、置換後のテキストを網羅した2次元配列を作成して、全てを一括で変換するというものです。

[[ /0/g, '0' ],
 [ /1/g, '1' ]]

上記の例だと、全角数字を半角数字に置換する事が出来ます。アルファベットや数字など法則性の高い置換に向いているスクリプトです。

前置きが少々長くなりましたが、今回はこちらのスクリプトを元に、全角を半角に変換するスクリプト、英単語の特定位置のみを大文字にするスクリプトをご紹介します。

住所などのデータを全角から半角へ一括変換するスクリプト

function convertSheetData() {
 const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
 const sheet       = spreadsheet.getSheetByName('元データ');
 const values      = sheet.getDataRange().getValues();

 //変換済データを2次元配列に格納
 const replaced = values.map(row => row.map(value => convertTwoByteCharacter_(value)));
 console.log(replaced);

 try{
   const newSheet = spreadsheet.insertSheet('変換済データ');
   newSheet.getRange(1, 1, replaced.length, replaced[0].length).setValues(replaced);
   newSheet.activate();
 }catch(error){
   console.log('シートは作成済です。');
   const ui          = SpreadsheetApp.getUi();
   const targetSheet = spreadsheet.getSheetByName('変換済データ');
   const response    = ui.alert('変換済データというシートは作成済です。上書きしてもよいですか?', ui.ButtonSet.YES_NO);
   
   switch (response){
     case ui.Button.YES:
     console.log('“はい” のボタンが押されました。');
     targetSheet.getRange(1, 1, replaced.length, replaced[0].length).setValues(replaced);
   break;
     case ui.Button.NO:
     console.log('“いいえ” のボタンが押されました。');
   break;
     default:
     console.log('処理が中断されました。');
   }//switch
 }
}



/**
* @param  {string} 全角数字を含むデータ
* @return {string} 半角数字のデータ
*/
function convertTwoByteCharacter_(targetWord){
 const twoByteCharacter  = '0123456789';
 const halfSizeCharacter = '0123456789';
 const list = twoByteCharacter.split('');

 const lists = list.map(
   (string, i) => [new RegExp(string, 'g'), halfSizeCharacter[i]]
 );

 //console.log(lists);

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

 return replaced

}

シートのスクリーンショット

スクリーンショット 2022-04-02 7.42.35
スクリーンショット 2022-04-02 11.07.54

元データが上書きされると、何かと困る事も多いかなと思って、新しいシートが作成され、そこにデータが貼り付けられます。シートが作成済の場合は、上書きしても問題ないか、アラート画面が表示されます。

シートを新規作成する場合、0から始まると書式設定の影響を受けてしまいますね。そう考えると書式設定を済ませた別シートを指定してあげた方がいいかもしれませんね。

sheet.getRange(1,1).setNumberFormat("text")

setNumberFormatsは、2次元配列が引数に指定する定義になっています。

あらかじめ、シート内の各セルの数字形式をいろいろなフォーマットで指定したい場合に、セル位置に対応した2次元配列でフォーマット文字列を定義します。

そして、setNumberFormatsで定義した2次元配列を引数にして実行すれば、セルの数字形式を事細かに設定可能です。ただ、そこまで細かな設定をするケースは少なく、また2次元配列を定義する手間も発生するため、基本的に使うのはsetNumberFormatとなります。

ボタンを使ったスクリプト書いた事がなくて苦戦しました。

こちら参考にさせてもらいました。

特定の単語の指定位置のみ大文字に変換するスクリプト

function myFunction(){
 const targetWord = 'dark-night';
 convertLowerToUpper_(targetWord, 1);
}



/**
* @param {string} 変換対象となる単語
* @param {number} 変換したい単語の位置 1番目の場合は0を指定
* 
*/
function convertLowerToUpper_(targetWord, start){
 const lower = 'abcdefghijklmnopqrstuvwxyz';
 const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
 
 //小文字の文字列を1次元配列化
 const lowerArray = lower.split('');
 console.log(lowerArray);

 /*
   文字列から5番目の値を取り出す
   console.log(`upper[4]: ${upper[4]}`); expected output E

   [[ /a/g, 'A' ],[/b/, B]]
   置換対象の正規表現と、置換後 A-Zまでを網羅した2次元配列を作成
 */

 const lists = lowerArray.map(
   (string, i) => [new RegExp(string, 'g'), upper[i]]
 );

 console.log(lists);

 const replaced = lists.reduce((acc, list) => acc.replace(...list), targetWord[start]);
 let newString  = '';

 //指定した位置の文字列を変換する
 for(let i = 0; i < targetWord.length; i++){
   if(i === start){
     newString += replaced;
     console.log(`${targetWord}の文字列から、${start} 番目の文字列 ${targetWord[start]}${replaced} で置き換える`);
   }else{
     newString += targetWord[i];
   }
 }
 console.log(newString);
 return newString

}

replaceメソッドでは、通常位置の指定ができません。今回のスクリプトでは、for文を使って力技で変換を実現しています。

aark-night → replace('a', 'A')
Aark-nightになってしまいます。

ログ

スクリーンショット 2022-04-02 7.35.34

きちんと2番目のaが、Aに変換されています。しかし、大抵の場合は、ドロップキャップ、単語や文章の初めの一文字目が大文字に変換する事が多いかと思います。

2023.3.3 加筆修正しました。ログの表記を変えました。

スプレッド構文

// replaceメソッドに必要な2つの引数を1次元配列にまとめている
// @param - 変換対象の文字列 or 正規表現
// @param - 変換後の文字列
const replaced = lists.reduce((acc, list) => acc.replace(...list), value);

//[[ /0/g, '0' ], [ /1/g, '1' ]]

listsは、置換対象をまとめた2次元配列
listは、1次元配列
replaceは、通常、引数を2つ必要とします。
valueが、変換対象の単語

サンプルコード

function sum(x, y, z) {
   return x + y + z;
}

const numbers = [1, 2, 3];
const result = sum(...numbers);

console.log(result);  // 6

一番簡単な例として、紹介されていたスクリプトですが、引数が3つ必要なところを、配列でまとめて割り当てることができるといったものになります。

etauさんのスクリプトは、replaceメソッドの2つの引数を配列で割り当てています。はぁ〜頭いいなぁーって思うスクリプト...。

Googleドキュメントでも便利に使える

function modifyStrings() {
    //ドキュメントの内容を取得する
  const document     = DocumentApp.getActiveDocument();
  const body         = document.getBody();
  const originalText = body.getText();
  console.log(originalText);
    
    //(※注)原文を置換後の文章で全て置き換える
  const replaced = replacedText_(originalText);
  body.setText(replaced);
  
}


/**
* 引数に指定した文字列を全て正規表現で置き換える
*
* @param  {string} string - 置換前の文字列
* @return {string} string - 置換語の文字列
*/
function replacedText_(string){

    //[置換対象, 置換後の文字列]
  const lists = [
    [/:/g,     ':'],
    [/スタート/g, ''],
    [/終了まで/g, ''],
  ];

  console.log(lists);

 //reduceの引数  (acc, [/:/g, ':']) 
  //@param {string}         acc - 置換語の文字列が格納される
  //@param {Array.<string>} current - には、正規表現と置換後の文字列がセットになった1次元配列が格納される
 //replaceの引数(reg, targetWord) 2つの引数に、残余引数構文を使用 [/:/g, ':']

 const replaced = lists.reduce((acc, list) => acc.replace(...list), string);
 console.log(`返還前`);
 console.log(`${string}\n`);

 console.warn(`変換後`);
 console.log(`${replaced}`);

 return replaced

}

久しぶりに自分のスクリプトを見たら、下記の部分が何をやっているか分からなかったので、コメントを加筆しました。

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

他にこんなスクリプト書いています。


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