LANG SELRCT

コードを書く場所

2018年4月26日木曜日

配列の末尾に要素を追加したい


["hello", "hi"]

という配列があって

"hey"を末尾に追加して以下のようにしたい

["hello", "hi", "hey"]


2つの方法で書いてみます
  • push
  • splice



コード.gs
function add_tail() {
  var array = ["hello", "hi"];
  var add_tail = "hey";
  array.push(add_tail);
  Logger.log(array);
}
意訳
この機能がやること
配列を用意して
末尾に追加したい要素を決めて
末尾に追加して
追加後の配列をログに出す




コード.gs
function add_tail() {
  var array = ["hello", "hi"];
  var add_tail = "hey";
  array.splice(array.length, 0, add_tail);
  Logger.log(array);
}
意訳
この機能がやること
配列を用意して
末尾に追加したい要素を決めて
末尾に追加して
追加後の配列をログに出す



array.splice(array.length, 0, add_tail)について

例の配列の要素はhelloとhiの2つ
→配列の要素の番号は0始まりでhelloは0番目でhiは1番目
→array.lengthで配列の要素数を取得すると2
→heyを追加したいのは配列の2番目のいちなのでarray.lengthの2を使って
array.splice(2, 0, add_tail)となるようにしている


実行結果


配列の先頭に要素を追加する


["hello", "hi"]

という配列があって

"hey"を先頭に追加して以下のようにしたい

["hey", "hello", "hi"]


2つの方法で書いてみます

  • unshift
  • splice




コード1.gs
function add_top() {
  var array = ["hello", "hi"];
  var add_top = "hey";
  array.unshift(add_top);
  Logger.log(array);
}
意訳
この機能がやること
配列を用意して
先頭に追加したい要素を
先頭に追加して
追加後の配列をログに出す




コード2.gs
function add_top() {
  var array = ["hello", "hi"];
  var add_top = "hey";
  array.splice(0, 0, add_top);
  Logger.log(array);
}
意訳
この機能がやること
配列を用意して
先頭に追加したい要素を
先頭に追加して
追加後の配列をログに出す




実行結果


2018年4月22日日曜日

Mathオブジェクトの備忘録


忘れがちなので使いそうなMathオブジェクトの備忘録


小数点以下切り捨て: Math.floor()
小数点以下切り上げ: Math.ceil()
小数点以下四捨五入: Math.round()

ランダムな数字: Math.random()
平方根: Math.sqrt()



コード.gs
function myFunction() {
  var Math_floor = Math.floor(1.55);
  Logger.log(Math_floor);

  var Math_floor2 = Math.floor((1.55) * 10) / 10;
  Logger.log(Math_floor2);

  var Math_ceil = Math.ceil(1.55);
  Logger.log(Math_ceil);

  var Math_ceil2 = Math.ceil((1.55) * 10) / 10;
  Logger.log(Math_ceil2);

  var Math_round = Math.round(1.55);
  Logger.log(Math_round);

  var Math_round2 = Math.round((1.55) * 10) / 10;
  Logger.log(Math_round2);

  var Math_random = Math.random()
  Logger.log(Math_random);

  var Math_squrt = Math.sqrt(9)
  Logger.log(Math_squrt);
}
意訳
この機能がやること
小数点第1以下の値を切り捨てて
ログに出す

小数点第2以下の値を切り捨て(引数の値を10倍して小数点の一を左に1つ移動してから小数点以下を切り捨てた値を10で割る)
ログに出す

小数点第1以下の値を切り上げて
ログに出す

小数点第2以下の値を切り上げ
ログに出す

小数点第1以下の値を四捨五入して
ログに出す

小数点第2以下の値を四捨五入して
ログに出す

0以上1未満の乱数を
ログに出す

引数の平方根を
ログに出す




実行結果


テキストボックスに削除ボタンを付ける


以下のように入力文字を削除する×アイコンを右端に表示する


ブラウザによって異なるようですが
以下の確認した環境では

<input type="search">

で表示できました


確認した環境
chrome バージョン: 65.0.3325.181(Official Build) (64 ビット)



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <body>
    <input type="search">
  </body>
</html>
意訳
これはHTML5文書です


searchボックス




2018年4月21日土曜日

配列内で重複する値の発生数を取得してオブジェクトを配列に入れて返す(発生件数の降順)


["ス", "モ", "モ", "も", "モ", "モ", "も", "モ", "モ", "の", "う", "ち"]

という配列から


重複件数が多い順に並べたオブジェクトを作りたい

 [
  {count=6.0, text=モ},
  {count=2.0, text=も},
  {count=1.0, text=う},
  {count=1.0, text=ち},
  {count=1.0, text=の},
  {count=1.0, text=ス}
]




コード.gs
function get_result(){
  var array = ["ス", "モ", "モ", "も", "モ", "モ", "も", "モ", "モ", "の", "う", "ち"];
  var result = get_match_count(array);
  var desc = sort_obj(result)
  Logger.log(desc);
}

function get_match_count(array){
  var sorted = array.sort();
  var arrays = [];
  var count;
  var unique_i;
  for(var i = 0; i < sorted.length; i++){
    var obj = {}
    var value = sorted[i];
    if(value === sorted[i-1]){
      count++;
      arrays[unique_i]["count"] = count;
    }else{
      count = 1;
      obj["text"] = value;
      obj["count"] = count;
      unique_i = arrays.length;
      arrays.push(obj);
    }
  }
  return arrays;
}

function sort_obj(arrays){
  var desc = arrays.sort(sorting);
  return desc;
}

function sorting(a, b){
  return b["count"] - a["count"];
}
意訳
この機能がやること
配列を用意して
get_match_countに渡して
結果をsort_objに渡して
ログに出す


この機能がやること
渡された配列をsortで並べ替えて(昇順)
結果を入れる配列を用意して
要素の重複件数を入れるcountの入れ物を用意して
要素を一意にした時のindexを指定するunique_iの入れ物を用意して
配列の数だけ以下を繰り返す
オブジェクトを新しく作る
配列内の値を一つずつ取得して
もしひとつ前の値と同じなら
countに1を足して
arrays内で現在targetにしているindexのcountの値に入れる
同じじゃなければ
countに1を入れて
obj{"text": value, 
"count": count}を作って
unique_iに現在のarraysの要素数を入れて(つまり一意の値の数)
arraysに追加して


出来上がったarraysを返す


この機能がやること
渡されたarraysのcountを降順に並べ替えた配列を
返す


この機能がやること
arrays内の値を比較して大きい順に並べ替えた配列に値を返す



実行結果



配列内で重複する値の発生数を取得してオブジェクトを配列に入れて返す


["す", "も", "も", "も", "も", "も", "も", "も", "も", "の", "う", "ち"]

という配列から


重複件数を取得して以下のようなオブジェクトを作りたい

[
  {count=1.0, text=う},
  {count=1.0, text=す},
  {count=1.0, text=ち},
  {count=1.0, text=の},
  {count=8.0, text=も}
]




コード.gs
function get_result() {
  var array = ["す", "も", "も", "も", "も", "も", "も", "も", "も", "の", "う", "ち"];
  var result = get_match_count(array);
  Logger.log(result);
}

function get_match_count(array) {
  var sorted = array.sort();
  var count = 1;
  var arrays = [];
  var target_i = 0;
  for (var i = 0; i < sorted.length; i++) {
    var obj = {}
    var value = sorted[i];
    if (value == sorted[i - 1]) {
      count++;
      arrays[target_i]["count"] = count; 
    } else {
      obj["text"] = value;
      obj["count"] = count;
      arrays.push(obj);
      target_i = i;
      count = 1;
    }
  }
  return arrays;
}
意訳
この機能がやること
配列を用意して
get_match_countに渡して
結果をログに出す


この機能がやること
渡された配列をsortで並べ替えて(昇順)
countの初期値を1にして
結果を入れる配列を用意して

配列の数だけ以下を繰り返す
オブジェクトを新しく作る
配列内の値を一つずつ取得して
もしひとつ前の値と同じなら
countに1を足して
arrays内で現在targetにしているindexのcountの値に入れる
同じじゃなければ
obj{"text": value, 
"count": count}を作って
arraysに追加して
target_iに現在のiを入れて
countを1に初期化する


出来上がったarraysを返す



実行結果




配列の中で特定の値がいくつ存在するか件数を取得したい


["す", "も", "も", "も", "も", "も", "も", "も", "も", "の", "う", "ち"]

という配列の中で

"も"

はいくつ存在するか



コード.gs
var count = 0;
function get_match_count() {
  var array = ["す", "も", "も", "も", "も", "も", "も", "も", "も", "の", "う", "ち"];
  var filtered = array.filter(judge);
  Logger.log([filtered, count]);
}

function judge(value_i, index) {
  var target = "も";
  pattern = "^" + target + "$";
  var regexp = new RegExp(pattern);
  var result = regexp.test(value_i);
  if (result === true) {
    count++;
    Logger.log(index)
  }
  return result;
}
意訳
countの初期値は0
この機能がやること
重複を含む配列
一致した値で新しい配列を作って
countと一緒にログに出す


この機能がやること
探す文字列を決める
その文字で始まってその文字で終わる→完全一致にして
正規表現オブジェクトを作って
渡されているvalue(配列内の各値)と一致したらtrueを、一致しなかったらfalseを返すtestを使って
もしtrueなら
countに1を足して
indexをログに出す

resultを返す



実行結果


 [[も, も, も, も, も, も, も, も], 8.0]

"も" は8個存在する



配列内の要素をfilterでユニークにしたい


 ["す", "も", "も"]

という配列から重複を除いた

 ["す", "も"]

という配列を作りたい



コード.gs
function get_unique(){
  var values = ["す", "も", "も"];
  var unique = values.filter(return_unique);
  Logger.log(unique);
}

function return_unique(value_i, index, array){
  var value_i_index = array.indexOf(value_i);
  var result = value_i_index === index;
  return result;
}
意訳
この機能がやること
重複を含む配列
重複のない一意の配列にして
ログに出す


この機能がやること(配列の各値, そのindex番号, 配列自身)
渡された値を配列の中で探して、最初に見つかったindex番号を取得して
引数で渡されているindex番号と同じかどうか判定して
結果をtrueかfalseで返す(trueの場合は新しい配列に値が追加される)



実行結果



補足


どういう動きをしているのか考えてみた


filterを使って
配列内で前から順番に値を探して
見つかった値のindex位置と
現在探している値のindex位置が同じなら
trueを返して新しい配列に追加する


配列が ["す","も","も"] の場合

arrayindexarray[index]indexOf(array[index])indexOf(array[index]) === index
["す","も","も"]0["す","も","も"]→す["す","も","も"]→00 === 0 → true
["す","も","も"]1["す","も","も"]→も["す","も","も"]→11 === 1 → true
["す","も","も"]2["す","も","も"]→も["す","も","も"]→11 === 2 → false


get_unique(value_i, index, array)
がやっていることをみると


0. get_unique("す", 0, ["す","も","も"])
["す","も","も"].indexOf("す")→0番目に見つかって、渡されたindexも0なのでtrueが返る


1. get_unique("も", 1, ["す","も","も"])
["す","も","も"].indexOf("も")→1番目に見つかって、渡されたindexも1なのでtrueが返る


2. get_unique("も", 2, ["す","も","も"])
["す","も","も"].indexOf("も")→1番目に見つかるが、渡されたindexは2なのでfasleが返る


2018年4月19日木曜日

LEFT, RIGHT関数で左右端の文字を削除する


A1に (あいうえお) という文字列が入っているときに

ABC
1(あいうえお)
2


()を除いた

あいうえお

だけを表示したい


編集メニューの「検索と置換」で ( と ) を消しても良いですが



LEFTとRIGHT関数でやってみる



B1に
=LEFT(A1,LEN(A1)-1)
を入れると
右端の ) を除ける
ABC
1(あいうえお)(あいうえお
2


C1に
=RIGHT(B1,LEN(B1)-1)
を入れると
左端の ( を除ける
ABC
1(あいうえお)(あいうえおあいうえお
2




-1を-2とかにするとその分だけ文字列が削除される



参考

LEFT
https://support.google.com/docs/answer/3094079

RIGHT
https://support.google.com/docs/answer/3094087

今月末の日を取得する


今月の末日を取得する例です

4月の場合は末日は4月30日なので
30日をend_dateで出してみる



コード.gs
function get_end_of_the_month() {
  var now = new Date();
  var this_year = now.getFullYear();
  var this_month = now.getMonth();
  var new_date = new Date(this_year, this_month + 1, 0);
  var end_date = new_date.getDate();
  Logger.log([new_date, end_date]);
}
意訳
この機能がやること
現在日時を取得して
西暦を取得して
月を取得して
来月の月初の一日前を取得して
末日の日を取得して
日付と日をログに出す



実行結果



2018年4月15日日曜日

入力した漢字の情報を表示する(JIS漢字水準、常用漢字、UTF16、16進数)


入力した漢字がJIS漢字水準のどれか、それは常用漢字か、ついでにUTF16と16進数も表示する



デモ
https://script.google.com/macros/s/AKfycbwy_MVWnJNHV4u61T-Nxdaua3znBRqKa9LxaQnEE0T50zx6uGM/exec


やっていること
  • 漢字一覧のJSONファイルを取得してJavaScriptで扱えるようにparseする
  • 入力された漢字の[UTF16, 16進数, JIS漢字水準 , 常用漢字]の値を取得する
  • それぞれを画面に表示する

事前に作っておくもの
  • JIS第一水準から第四水準と常用漢字の一覧から以下のようなJSONファイル

{
  "漢字1": [ UTF16, 16進数, JIS漢字水準 , 常用漢字],
  "漢字2": [ UTF16, 16進数, JIS漢字水準 , 常用漢字],
...
}

JSONファイルの中身


それを作ったJSONファイル
(個人のGoogleドライブ上に置いているため、予告なく共有設定を切ることもあります)
https://drive.google.com/file/d/1nP585m4LmmoaVlXDDCQPEKEr0pj6FIje/view?usp=sharing


JSONファイルを作るための元データ(wikipediaの情報を元にシートにまとめたもの)



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}

var FILE_ID = "1HmoOYSCFh3tq6u22o5eE4hhmjwsle7hv";
function get_jobj_gs() {
  var file = DriveApp.getFileById(FILE_ID);
  var blob = file.getBlob()
  var data = blob.getDataAsString();
  var jobj = JSON.parse(data);
  return jobj;
}
意訳
この機能がやること
指定したhtmlファイルを表示する


漢字のデータが入ったJSONFILE_IDを指定(Googleドライブ)
この機能がやること
FILE_IDからファイルを取得して
ファイルのblobを取得して
データを取得して
オブジェクトに変換して
返す




index.html
<!DOCTYPE html>
<head>
    <style>
        .kanji {
            width: 120px;
            font-size: 60px;
            border: none;
        }

        .tb {
            width: 120px;
            font-size: 18px;
            border: none;
        }

        table {
            border: solid 1px #000000;
            border-collapse: collapse;
            margin-left: auto;
            margin-right: auto;
        }

        td {
            border: solid 1px silver
        }
    </style>
</head>
<html>
<body>
    <table>
        <tbody>
            <tr>
                <td>漢字</td>
                <td><input type="text" id="kanji" class="kanji"></td>
            </tr>
            <tr>
                <td>UTF16</td>
                <td><input type="text" id="utf16" class="tb" readonly></td>
            </tr>
            <tr>
                <td>16進数</td>
                <td><input type="text" id="hexadecimal" class="tb" readonly></td>
            </tr>
            <tr>
                <td>JIS</td>
                <td><input type="text" id="category" class="tb" readonly></td>
            </tr>
            <tr>
                <td>常用</td>
                <td><input type="text" id="joyo" class="tb" readonly></td>
            </tr>
        </tbody>
    </table>
    <script>
        var kanji = document.getElementById("kanji");
        var utf16 = document.getElementById("utf16");
        var hexadecimal = document.getElementById("hexadecimal");
        var category = document.getElementById("category");
        var joyo = document.getElementById("joyo");
        var obj;

        kanji.focus()

        document.addEventListener('DOMContentLoaded', get_jobj);
        kanji.onkeyup = kanji_keyup;

        function get_jobj() {
            google.script.run
                .withFailureHandler(onFailure)
                .withSuccessHandler(onSuccess)
                .get_jobj_gs();
        }

        function onSuccess(jobj) {
            obj = jobj;
        }

        function onFailure(e) {
            alert([e.message, e.stack]);
        }

        function kanji_keyup(e) {
            var kanji = this.value[0];
            var key_code = e.keyCode;
            if (key_code == 8) {
                clear_result();
                get_result(kanji);
            } else {
                get_result(kanji);
            }
        }

        function get_result(kanji) {
          if(/[㐂-頻]/.test(kanji)){
            utf16.value = obj[kanji][0];
            hexadecimal.value = obj[kanji][1];
            category.value = obj[kanji][3];
            joyo.value = obj[kanji][4];
          }
        }

        function clear_result() {
            utf16.value = '';
            hexadecimal.value = '';
            category.value = '';
            joyo.value = '';
        }
    </script>
</body>
</html>
意訳
 


kanjiのスタイル
幅
文字サイズ
枠線


tbのスタイル
幅
文字サイズ
枠線


tableのスタイル
枠線
枠線を離さず表示
左の余白
右の余白


taのスタイル
枠線








漢字
漢字の入力欄


UTF16
UTF16の出力欄


16進数
16進数の出力欄


JIS
JISの出力欄


常用
常用漢字の出力欄




idがkanjiの要素を取得
idがutf16の要素を取得
idがhexadecimalの要素を取得
idがcategoryの要素を取得
idがjoyoの要素を取得
objの入れ物

kanjiにフォーカス

DOMの内容が読み込まれたらget_jobjを実行する
kanji内でキーが上がったらkanji_keyupを実行する

この機能がやること
.gsのスクリプトを実行する
失敗したらonFailureを実行する
成功したらonSuccessを実行する
実行する.gsスクリプトはget_jobj_gs


この機能がやること
渡されたjobjをobjに入れる


この機能がやること
受け取ったエラーをアラートに出す


この機能がやること
入力された先頭の漢字をkanjiに入れて
押されたキーコードを取得して
もし8なら(8はdeleteキー)
clear_resultを実行して
get_resultにkanjiを渡す
それ以外なら
get_resultにkanjiを渡す



この機能がやること
もし渡されたkanjiが㐂-頻の範囲にあるなら(JIS第一から第四水準がこの範囲内に含まれる前提)
objからutf16の値を取得して
objからhexadecimalの値を取得して
objからcategoryの値を取得して
objからjoyoの値を取得してそれぞれの出力欄に入れる



この機能がやること
utf16の値を空にして
hexadecimalの値を空にして
categoryの値を空にして
joyoの値を空にする






スプレッドシートでマクロの記録


マクロの記録が出来るようになったらしい

  • G Suiteのみの機能(2018/04/12現在)
  • 記録するとApps Scriptが作成されて編集できる


参考

Google スプレッドシートでタスクを自動化する
https://support.google.com/docs/answer/7665004

Additional details on new macro recorder and formatting options in Google Sheets
https://gsuiteupdates.googleblog.com/2018/04/new-macros-google-sheets.html

改行⇔カンマに置換する


入力された文章を以下のように変更したい

  • 改行をカンマに置換する
  • カンマを改行に置換する


作ったもの
改行→カンマ

カンマ→改行


デモ(Apps Script)
https://script.google.com/macros/s/AKfycbyPGHfI3WyEx-ruw2ug3llMIDVSGkf3EF1-CLhAcp69aa7cxgw/exec



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <head>
    <style>
    .ta {
      width: 360px;
      height: 120px;
    }
  </style>
  </head>
  <body>
    <textarea id="ta" class="ta"></textarea>
    <br>
    <button id="break_bt">改行をカンマに変える</button>
    <button id="replace_bt">カンマを改行に変える</button>
    <br>
    <textarea id="result" class="ta"></textarea>
    <script>
      var tb = document.getElementById("tb");
      var ta = document.getElementById("ta");
      var result = document.getElementById("result");
      var break_bt = document.getElementById("break_bt");
      var replace_bt = document.getElementById("replace_bt");

      ta.focus();      

      break_bt.onclick = run;
      replace_bt.onclick = run;
      
      function run(){
        var before;
        var after;
        var flag = this.id;
        if(flag == "break_bt"){
          before = "\n";
          after = ", ";
        } else if(flag == "replace_bt"){
          before = ",[  ]*";
          after = "\n";
        }
        var pattern = new RegExp(before, "g");
        result.value = ta.value.replace(pattern, after); 
      }
    </script>
  </body>
</html>
意訳
 



taのスタイル
幅
高さ




入力用のテキストエリア

改行→カンマに変換するボタン
カンマ→改行に変換するボタン

結果を出力するテキストエリア

idがtbの要素を取得
idがtaの要素を取得
idがresultの要素を取得
idがbreak_btの要素を取得
idがreplace_btの要素を取得

taをフォーカスする

break_btがクリックされたらrunを実行する
replace_btがクリックされたらrunを実行する

この機能がやること
変換前の文字の入れ物
変換後の文字の入れ物
クリックされたボタンのid
idがbreak_btなら
beforeは改行
afterはカンマ(と半角スペース)
idがreplace_btなら
beforeはカンマ(と全角半角スペースいくつでも)
afterは改行

/before/gのパターンを作って
ta.valueをafterで置換した値をresultの値に入れる







入力された文章を指定した文字で置換する


入力された文章を以下のように変更したい

  • 特定の文字の後で改行を入れる
  • 特定の文字を削除する
  • 特定の文字を別の文字に置換する


作ったもの


デモ(Apps Script)
https://script.google.com/macros/s/AKfycbxtOVIOMDb1mVUV5UvljHytpHrqwHAVrdvLyUxf5TOIoSq_nbOb/exec



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <head>
    <style>
    .ta {
      width: 360px;
      height: 120px;
    }
  </style>
  </head>
  <body>
    <textarea id="ta" class="ta"></textarea>
    <br>
    <input type="text" id="tb" class="tb">を 
    <button id="break_bt">直後で改行する</button>
    <button id="delete_bt">削除する</button>
    <br>
    <input type="text" id="tb2" class="tb">に 
    <button id="replace_bt">置換する</button>
    <br>
    <textarea id="result" class="ta"></textarea>
    <script>
      var tb = document.getElementById("tb");
      var tb2 = document.getElementById("tb2");
      var ta = document.getElementById("ta");
      var result = document.getElementById("result");
      var break_bt = document.getElementById("break_bt");
      var delete_bt = document.getElementById("delete_bt");
      var replace_bt = document.getElementById("replace_bt");
      
      break_bt.onclick = run;
      delete_bt.onclick = run;
      replace_bt.onclick = run;
      
      ta.focus();
      
      function run(){
        var flag = this.id;
        var after = get_after(flag);
        var pattern = new RegExp(tb.value, "g");
        result.value = ta.value.replace(pattern, after);
      }
      
      function get_after(flag){
        var after = "";
        switch(flag){
          case "break_bt":
            after = tb.value + "\n";
            break;
          case "delete_bt":
            after = "";
            break;
          case "replace_bt":
            after = tb2.value;
            break;
        }
        return after;
      }
    </script>
  </body>
</html>
意訳
 



taのスタイル
幅
高さ




入力用のテキストエリア

改行、削除、置換対象の文字を入れるテキストボックス
改行ボタン
削除ボタン

このテキストボックスに入力した文字に置き換える
置換ボタン

結果を出力するテキストエリア

idがtbの要素を取得
idがt2の要素を取得
idがtaの要素を取得
idがresultの要素を取得
idがbreak_btの要素を取得
idがdelete_btの要素を取得
idがreplace_btの要素を取得

break_btがクリックされたらrunを実行する
delete_btがクリックされたらrunを実行する
replace_btがクリックされたらrunを実行する

taをフォーカスする

この機能がやること
クリックされたボタンのidを取得して
get_afterに渡して結果を得る
正規表現でパターンを作成して
置換して出力する


この機能がやること
afterの入れ物を作って
渡されたflagによってafterに入れる値を変える
break_btの場合
afterにtb.value + 改行を入れる

delete_btの場合
afterには何も入れない

replace_btの場合
afterにtb2.valueを入れる


afterに入れた値を返す







2018年4月9日月曜日

配列内で重複する値の発生数を取得してオブジェクトで返す


var values = ["take", "your", "time", "take", "care", "of", "your", "take"]

上のような配列があって
この中で同じ値がいくつあるか


以下のようなオブジェクトで返したい

{"care":1,"of":1,"take":3,"time":1,"your":2}



コード.gs
function result(){
  var values = ["take", "your", "time", "take", "care", "of", "your", "take"];
  var obj = get_result_obj(values);
  Logger.log(JSON.stringify(obj));
}

function get_result_obj(values) {
  var num = 0;
  var word = [];
  var count = [];
  var obj = {};
  values = values.sort();
  for (var i = 0; i < values.length; i++) {
    if(i == 0){
      word.push(values[0]);
      count.push(1);
      num = 0;
    }else if(values[i] == values[(i-1)]) {
      count[num] = count[num] + 1;
    }else {
      word.push(values[i]);
      count.push(1);
      num = num + 1;
    }
    obj[values[i]] = count[num];
  }
  Logger.log([word, count]);
  return obj;
}
意訳
この機能がやること
配列を用意して
get_result_objに渡して
結果をJSON形式でログに出す


この機能がやること
numに0を入れて
wordの配列を用意して
countの配列を用意して
objという空のオブジェクトを用意して
渡されたvalues配列をソートして
配列の要素の数だけ以下を繰り返す
もし最初の処理なら(つまりiが0の場合)
word配列にvaluesの先頭(0番目)の値を追加して
countに1を追加して
numに0を入れる
もしi番目の値が1つ前の値と同じなら(つまり重複する値の場合)
count配列のnum番目の値に1を足す
それ以外なら
word配列にi番目の値を追加して
count配列に1を追加して
numに1を足す

objオブジェクトでvaluesのi番目の値をkeyとするプロパティのvalueに、count配列のnum番目の値を入れる(これで 単語: 件数の形になる)

word配列とcount配列をログに出して
objオブジェクトを返す



モーダルに閉じるボタンをつける


モーダルを作る で作ったモーダルの右上に
このような閉じるボタン(✕)をつける




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<head>
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
  .modal_back {
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.4);
    display: none;
    position: fixed;
    left: 0;
    top: 0;
    z-index: 1;
  }

  .modal_content {
    width: 30%;
    height: 30%;
    border: 2px solid gray;
    padding: 15px;
    margin: 10% auto;
    background-color: white;
  }
  
  .clear_bt {
    float: right;
    color: gray;
  }
</style>
</head>
<body>
  <button id="bt">Modal</button>
  <div id="modal_back" class="modal_back">
    <div class="modal_content">
      <i id="clear_bt" class="material-icons clear_bt">clear</i>
      <p>このエリアの外をクリックすると閉じます</p>
    </div>
  </div>
  <script>
    var modal = document.getElementById('modal_back');

    document.getElementById("bt").onclick = open_modal;
    modal.onclick = close_modal;

    function open_modal() {
      modal.style.display = "block";
    }

    function close_modal(event) {
      if (event.target == modal || event.target.id == 'clear_bt') {
        modal.style.display = "none";
      }
    }
  </script>
</body>
</html>
意訳
これはHTML5文書です


Material Iconsを利用できるようにする

モーダルの背景のスタイル
幅100%
高さ100%
背景色と透明度
表示しない
位置を固定する
左の余白0
上の余白0
最前面にする


モーダルの中身のスタイル
幅を決める
高さを決める
枠線の幅2px 1本線 gray
内側の余白15px
上から10%の距離
背景色white


閉じるボタンのスタイル
右に寄せる
文字色gray




ボタンを置く
モーダルの背景を置く
モーダルの中身を置く
閉じるボタンを置く
段落にテキストを置く



id が modal_back の要素を取得する

id が bt の要素をクリックしたらopen_modalを実行する
id が modal の要素がクリックされたらclose_modalを実行する

この機能がやること
id が modal の要素を block 要素として表示する


この機能がやること
もしクリックされた要素の id が modal なら
その要素を非表示にする








個人的に使っている環境設定やアプリなど


macOSをクリーンインストールした時に追加したものなどを更新していく個人的な備忘録


macOS High Sierra
https://www.apple.com/jp/macos/high-sierra/
 システム環境設定 > アクセシビリティ > マウスとトラックパッド
  トラックパッドオプション ドラッグを有効にする 3本指のドラッグに設定

 システム環境設定 > 省エネルギー
  バッテリー ディスプレイをオフにするまでの時間を設定

 システム環境設定 > Mission Controll
  ホットコーナーを設定

 システム環境設定 > キーボード
  F1、F2などのキーを標準のファンクションキーとして使用
 
 システム環境設定 > トラックパッド > ポイントとクリック
  軌跡の速さ


Google日本語入力
https://www.google.co.jp/ime/


Chrome
https://www.google.co.jp/chrome/


Atom
https://atom.io/


Sublime
https://www.sublimetext.com/


iTerm2
https://www.iterm2.com/
 iTerm2 >  Preferences > Profiles
  Colors : Coler Presets
  Window : Transpalency
  Terminal : Unlimited scrollback


LINE
https://itunes.apple.com/us/app/line/id539883307


Node.js
https://nodejs.org/en/download/
からダウンロードしたnode-v8.11.1.pkgを開いてインストール


clasp
https://developers.google.com/apps-script/guides/clasp
https://codelabs.developers.google.com/codelabs/clasp/#0
https://github.com/google/clasp


Kindle / Kindle Cloud Reader
https://www.amazon.co.jp/gp/digital/fiona/kcp-landing-page/ref=klp_mn


Xcode
https://itunes.apple.com/jp/app/xcode/id497799835?mt=12


Anaconda
https://www.anaconda.com/download/#macos


Flask
http://flask.pocoo.org/
$ pip install Flask


Go
https://golang.org/dl/
https://tour.golang.org/welcome/1


Home brew
https://brew.sh/index_ja


Mecab
http://taku910.github.io/mecab/
$ brew install mecab
$ brew install mecab-ipadic


SourceTree
https://www.sourcetreeapp.com/


Bitbucket
https://bitbucket.org/product


GitHub
https://github.com/


Qiita
https://qiita.com/


GarageBand
https://itunes.apple.com/jp/app/garageband/id682658836?mt=12&ls=1
https://help.apple.com/garageband/mac/10.2/?lang=ja ヘルプ


Song-Maker
https://musiclab.chromeexperiments.com/Song-Maker/


Chrome Canvas
https://canvas.apps.chrome/


Singer Song Writer Lite 9(9.5) <Windows10>
https://www.ssw.co.jp/products/ssw/win/sswlt9w/index.html

音色リスト
https://www.ssw.co.jp/products/ssw/mac/sswlt30m/vsc_1.htm


Chrome Remote Desktop
https://chrome.google.com/webstore/category/extensions
http://www.atmarkit.co.jp/ait/articles/1301/30/news060.html 参考記事


Ruby
https://www.ruby-lang.org/ja/
$ gem install rspec


Cloud9
https://c9.io/dashboard.html


Visual Studio Code
https://code.visualstudio.com/
ClaspでType Scriptを使うためにインストールした
コマンドラインもついていて使いやすい


Type Script (Claspで使う)
https://developers.google.com/apps-script/guides/typescript


ES Lint
https://eslint.org/
VS Codeのプラグインとしてインストールした




2018年4月8日日曜日

map文を使う


mapを使って新しい配列を返すコードの例



コード1.gs
function do_map() {
  var values = ["hello", "hi", "hey"];
  var result = values.map(function(value){
    return value + "!!";
  }); 
  Logger.log(result);
}
意訳
この機能がやること
配列を用意する
配列の要素をひとつずつ無名関数に渡して
!!をくっつけて新しい配列に返す

結果をログに出す



実行結果



別の書き方

コード2.gs
function do_map2() {
  var values = ["hello", "hi", "hey"];
  var result = values.map(get_result); 
  Logger.log(result);
}

function get_result(value){
  var result = value + "!!";
  return result;
}
意訳
この機能がやること
配列を用意する
配列の要素をひとつずつget_resultに渡して
結果をログに出す


この機能がやること
渡された値に!!をくっつけて
返す(新しい配列に)



関連記事

似ているforEachは返り値がない



参考

Array.prototype.map()

毎日特定の日時ちょうどに実行するトリガーを作る


今回やること
毎日12:55に自分宛てにメールを送信する


それを実現するためにやること
  • 毎日11時〜12時に定期実行するトリガーを登録しておく
  • そのトリガーの関数内で、当日の12:55に実行するトリガーを登録する

時系列でみると
時系列
実行するトリガー
実行する処理
11時
add_temp_trigger
既存のsend_mailトリガーを削除
新規のsend_mailトリガーを登録
12時
12:55
send_mail
メールが送信される



実際に登録するトリガーを見るとこうなる



前提知識:GASのトリガーで実現できること
  • 「日タイマー」を設定すると毎日X時〜Y時の間に特定の関数を実行できる
  • 「特定の日時」で2018-04-08 12:55などを設定するとその日時に実行できる
  • ひとつのトリガーで「日タイマー」と「特定の日時」を同時に使うことはできない

やりたいこと:毎日12:55に特定の関数を実行したい
手順を書き出してみる
  1. まず実行したい関数を書く
  2. 「特定の日時」を指定して手順1の関数をトリガーに登録する
  3. 指定した日時にコードが自動で実行される
  4. 手順2で登録したトリガーは実行後も残っているので削除する
  5. 手順2と4を毎日繰り返す

手順5を自動化したい
  • 毎日「特定の日時」に実行する関数を自動でトリガーに登録して、使い終わったそのトリガーを自動で削除する



コード.gs
function set_project_trigger(){
  var date = new Date();
  ScriptApp.newTrigger("add_temp_trigger")
  .timeBased()
  .everyDays(1)
  .atHour(11)
  .create();
}

function add_temp_trigger() {
  delete_temp_trigger();
  var date = new Date();
  date.setHours(12);
  date.setMinutes(55);
  var trigger = ScriptApp.newTrigger("send_mail")
    .timeBased()
    .at(date)
    .create();
}  

function send_mail(){
  var mail_address = Session.getActiveUser().getEmail();
  MailApp.sendEmail(mail_address, "実行したスクリプトID", ScriptApp.getScriptId());
}

function delete_temp_trigger() {
  var allTriggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < allTriggers.length; i++) {
    if (allTriggers[i].getHandlerFunction() == "send_mail") {
      ScriptApp.deleteTrigger(allTriggers[i]);
      break;
    }
  }
}
意訳
この機能がやること
現在日時を取得する
add_temp_triggerを
時間主導型で
毎日
11時(〜12時の間)に実行する
トリガーを登録する


この機能がやること
使い終わったトリガーを削除する
現在日時を取得して
時刻を当日の12時
55分に設定して
send_mailを
時間主導型で
設定した日時に実行する
トリガーを登録する


この機能がやること
スクリプトを実行しているユーザのメールアドレスを取得して
実行したスクリプトIDをmaiで送信して


この機能がやること
このスクリプトに設定されているすべてのトリガーを取得して
そのトリガーの数だけ以下を繰り返す
もしトリガーに設定されている関数名が"send_mail"なら
プロジェクトのトリガーから削除して
for文から抜ける





試してみる


やることは add_temp_trigger を以下のようにトリガーに登録するだけ

これは毎日add_temp_triggerを実行するためのトリガーなので、故意に消さない限り残り続けます

このトリガーは編集メニューから直接登録しても良いですし set_project_trigger() を実行することでも登録できます
(set_project_trigger() は最初にこれを登録するためだけのコードなので使っても使わなくても良いですが、2日おきとか3日おきとかにしたい場合は、everyDays(1)をeveryDays(2)とかeveryDays(3)にするとよさそう)

編集メニューから登録する手順がわからない場合


以下は自動で行われる

毎日午前11時〜12時(正午)の間に send_mail を トリガーに登録するadd_temp_trigger が自動で実行される
そのときにプロジェクトのトリガーを見ると、send_mailが「特定の日時」でトリガーに登録されている


「特定の日時」である「2018-04-08 12:55」に send_mail が実行されたあと delete_temp_trigger() も自動で実行されて

2018-04-08 12:55の send_mail トリガーは削除される


翌日(2018-04-09)も午前11時〜12時(正午)の間に send_mail を トリガーに登録するadd_temp_trigger が自動で実行されて
send_mailトリガーが「特定の日時」で「2018-04-09 12:55」に登録されて、その時間に実行されて、削除されて...が毎日定期的に繰り返される


定期的な処理が不要になったら add_temp_trigger をプロジェクトのトリガーから削除する


参考

Installable Triggers
https://developers.google.com/apps-script/guides/triggers/installable#errors_in_triggers

everyDays(n)
https://developers.google.com/apps-script/reference/script/clock-trigger-builder#everyDays(Integer)


参考にさせていただいたQiita記事
https://qiita.com/sumi-engraphia/items/465dd027e17f44da4d6a



2018年4月7日土曜日

スクリプトの実行途中で処理を一時的に止める


Utilities.sleep(ミリ秒)
で処理を一時的に止めることができる

最大5分(300000ミリ秒)



コード.gs
function do_sleep(){
  Logger.log("2秒待つ");
  Utilities.sleep(2000);
  Logger.log("2秒待つ");
  Utilities.sleep(2000);
  Logger.log("2秒待つ");
}
意訳
この機能がやること
ログに出す
2秒待つ
ログに出す
2秒待つ
ログに出す







実行したスクリプトのURLとfunction名をメールの本文に記載する


スクリプトからメールを送信するときに
実行したスクリプトのURLとfunction名をメールの本文に記載する



コード.gs
function send_mail() {
  var mail_address = Session.getActiveUser().getEmail();
  var func_name = arguments.callee.name;
  var summary = "スクリプトから送信したメール";
  var body = "このメールは以下のスクリプトから送信されました\n" + get_script_url() + "\n" + func_name;
  MailApp.sendEmail(mail_address, summary, body);
}

function get_script_url(){
  var script_id = ScriptApp.getScriptId();
  var script_url = "https://script.google.com/d/" + script_id + "/edit";
  return script_url;
}
意訳
この機能がやること
スクリプトを実行しているユーザのgmailアドレスを取得して
実行しているfunction名を取得して
メールの件名を設定して
メールの本文を設定して
メールを送信する


この機能がやること
スクリプトのIDを取得して
スクリプトのURLを作って
返す



送信されるメール



スクリプト内でスクリプトIDを取得する



スクリプトのIDを取得する


コード1.gs
function get_script_id(){
  var script_id = ScriptApp.getScriptId();
  Logger.log(script_id); 
}
意訳
この機能がやること
開いているスクリプトファイルのIDを取得して
ログに出す



スクリプトのURLをログに出す


コード2.gs
function get_script_url(){
  var script_id = ScriptApp.getScriptId();
  var script_url = "https://script.google.com/d/" + script_id + "/edit";
  Logger.log(script_url);
}
意訳
この機能がやること
開いているスクリプトファイルのIDを取得して
URLの文字列を作って
ログに出す



JavaScriptで時間を設定する


西暦/月/日/時:分:秒:ミリ秒 を設定するコードの例

2020年1月2日3時4分5秒006ミリ秒を設定してログに出して
Google Apps Scriptでフォーマットしてみる



コード.gs
function set_datetime(){
  var date = new Date();  
  date.setFullYear(2020);
  date.setMonth(0);
  date.setDate(2); 
  date.setHours(3);
  date.setMinutes(4);
  date.setSeconds(5);
  date.setMilliseconds(6);
  Logger.log(date);
  Logger.log(format_date(date));
}

function format_date(date){
  return  Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd/HH:mm:ss:SSS');
}
意訳
この機能がやること
現在日時を取得する
西暦を設定する
月を設定する(月は["Jan", "Feb", "Mar"..., "Dec"]の配列で、0はJan→日本語では1月)
日を設定する
時を設定する
分を設定する
秒を設定する
ミリ秒を設定する
dateをログに出す
フォーマットしたdateをログに出す


この機能がやること
dateを東京時間でミリ秒までフォーマットして返す




実行結果



補足


(以下、疑問に思ったことの備忘録)

setMonthだけなぜ 0 始まりなんだろう

上のコード.gsで疑問に思うのは月だけ 0 で始まる点

1月はsetMonth(0)
2月はsetMonth(1)
3月はsetMonth(2)
4月はsetMonth(3)
5月はsetMonth(4)
6月はsetMonth(5)
7月はsetMonth(6)
8月はsetMonth(7)
9月はsetMonth(8)
10月はsetMonth(9)
11月はsetMonth(10)
12月はsetMonth(11)


上のコード.gsの中の
var date = new Date()

Logger.log(date)
のログを見ると

Thu Jan 02 03:04:05 GMT+09:00 2020

このように「月」は「数値」ではなく 「Jan」 という「英語で1月」を表す「January」の略で、「日本語では1月」を表す「文字列」になっている

setMonthを使う場合は
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
という文字列を要素に持つ配列があって
0番目はJan、11番目はDecを表すと考えたらよいのかも


2018年4月4日水曜日

選択されているラジオボタンのidを取得する



選択されているラジオボタンの値を取得する ことはできたけれど
これだと id を取得できないので
checkedになっている要素を見つけてあげて
そこからidを取得してみる



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<body>
  <form id="form1">
    <input type="radio" name="radio1" id="radio1_1" value="yes" checked="checked">
    <label for="radio1_1">はい</label>
    <br>
    <input type="radio" name="radio1" value="no" id="radio1_2">
    <label for="radio1_2">いいえ</label>
  </form>
  <br>
  <button type="button" id="bt">ボタン</button>
  <script>
    document.getElementById("bt").onclick = get_radio;

    function get_radio() {
      var form = document.getElementById("form1");
      var radio1 = form.radio1;
      var elem = "";
      for (var i = 0; i < radio1.length; i++) {
        if (radio1[i].checked) {
          elem = radio1[i];
        }
      }
      var elem_id = elem.id;
      alert(elem_id);
    }
  </script>
</body>
</html>
意訳
  


form
ひとつめのラジオボタン
そのラベル

ふたつめのラジオボタン
そのラベル


ボタン

idがbtの要素がクリックされたらget_radioを実行する

この機能がやること
idがform1の要素を取得して
そのradio1という名前を持つ要素を取得して
elemの入れ物を用意して
radio1の要素の数だけ以下を繰り返す
もしradio1の要素を順番に見て、もしチェックされていたら
elemに入れる
それ以外は何もせずに次の要素を見る

elemのidを取得して
アラートに表示する






2018年4月2日月曜日

要素の表示判定でoffsetTopを試してみる


親要素がdisplay: noneの子要素が
画面に表示されているかどうかを知りたくて試したコードです

表示されていない場合は 0 が返ってくるので
非表示の判定に利用できそう



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <head>
    <style>
    .display_none {
      display: none;
    }
    </style>
  </head>
  <body>
  <span class="display_none">
    <textarea id="ta">hello</textarea>
  </span> 
  <span>
    <textarea id="ta2">world</textarea>
  </span>  
  <script>
    var ta = document.getElementById("ta");
    var ta2 = document.getElementById("ta2");
    alert(ta.offsetTop)
    alert(ta2.offsetTop)
  </script>
  </body>
</html>

意訳
  



display_noneのスタイル
非表示にする




非表示のspan
テキストエリア

span
テキストエリア


idがtaの要素を取得する
idがta2の要素を取得する
上部からのtaの距離をアラート
上部からのta2の距離をアラート







実行結果

表示されていないtaのoffsetTop


表示されているta2のoffsetTop


ta2にはdisplay_noneを設定していないので表示される