LANG SELRCT

Apps Script Reference  (Create: Create new Spreadsheet | Create new Apps Script

Friday, March 30, 2018

全角英数を半角英数にして大文字を小文字にする


全角英数→半角英数→小文字に変換するコードの備忘録


全角英数
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz



全角を半角にして
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz



大文字を小文字にする
0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz



コード.gs
function zen_han_lower() {
  var zen = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  var han = zen_han(zen);
  var lower = get_lower(han);
  Logger.log([zen, han, lower]);
}

function zen_han(zen) {
  var han = "";
  var pattern = /[A-Za-z0-9]/;
  for (var i = 0; i < zen.length; i++) {
    if(pattern.test(zen[i])){
      var letter = String.fromCharCode(zen[i].charCodeAt(0) - 65248);
      han += letter;
    }else{
      han += zen[i];
    }
  }
  return han;
}

function get_lower(han){
  var lower = han.toLowerCase();
  return lower;
}
意訳
この機能がやること
全角英数字を用意して
zen_han()に渡して半角にした結果を受け取って
それをget_lower()に渡して小文字にした結果を受け取って
ログに出す


この機能がやること
半角の入れ物を用意して
全角英数のパターンを用意して
受け取った全角文字列の数だけ以下を繰り返す
文字が全角英数なら
半角英数に変換して
hanに追加して
全角英数以外なら
そのままhanに追加する


出来上がったhanを返す


この機能がやること
受け取った半角英数を小文字にして
返す



実行結果




Thursday, March 29, 2018

特定の列に特定の値が入っている行を削除する


スプレッドシートで特定の列に特定の値が入っている行を削除したくて書いたコードです


例として

  • 2行目から下に見ていき
  • B列に "重複" という値が入っている場合
  • その列を削除する


以下に例示したコードは筆者の環境で実行した時に書いたものなので、あくまで参考程度のものとしてみてください
行が誤って削除された場合も変更履歴から復元できるケースもありますが、削除する場合は充分テストをしてから実行することをオススメします



コード.gs
function delete_duplication(){
    var sh = SpreadsheetApp.openByUrl(SS_URL).getSheets()[0];
    var last_row = sh.getLastRow();
    for(var i = 2; i < last_row; i++){
      var range = sh.getRange("B"+ i);
      var value = range.getDisplayValue();
      if(value == "重複"){
        var start_row = i;
        var num_row = 1;
        sh.deleteRows(start_row, num_row);
        i = i - 1;
      }
    }
}
意訳
この機能がやること
シートを取得して(例では開いているシートの先頭にあるシート)
データが入っている最終行を取得して
2行目から最終行まで以下を繰り返す
B列を見て
表示されている値を取得して
"重複"なら
その行から
1行分を指定して
行を削除する
i の値を元に戻す("重複"の行が連続する場合、削除後に1行分上にずれるため、同じ行を見に行かないとズレた行が"重複"の場合にその行を削除できない)





関連記事

シートの行を削除する
シートの列内の重複データを見つける関数


Node.insertBefore()で要素を追加する


Node.insertBefore を使って
指定した要素の前後に要素を追加するコードを書きました


このdiv要素を基準に追加する



指定する要素は3つ
  • 親要素
  • 挿入する要素
  • どの要素の前に挿入するか
親要素.insertBefore(挿入する要素, この要素の前に)



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




index.html
<!DOCTYPE html>
<html>
  <body>
  <div id="main">
    <div id="sub">このdiv要素を基準に追加する</div>
    <button id="before">before</button>
    <button id="after">after</button>
  </div>
    <script>
    var main = document.getElementById("main");
    var sub = document.getElementById("sub");
    var before = document.getElementById("before");
    var after = document.getElementById("after");
    var before_num = 0;
    var after_num = 0;
    
    before.onclick = before_clicked;
    after.onclick = after_clicked;
    
    function before_clicked(){
      before_num ++;
      var div = document.createElement("div");
      div.textContent = "前に追加" + before_num;
      main.insertBefore(div, sub);
    }
    
    function after_clicked(){
      after_num ++;
      var div = document.createElement("div");
      div.textContent = "後ろに追加" + after_num;
      main.insertBefore(div, sub.nextSibling); 
    }
    </script>
  </body>
</html>
意訳
 


main_divのdiv
sub_divのdiv
前に追加するボタン
後ろに追加するボタン


idがmain_divの要素を取得
idがsub_divの要素を取得
idがbeforeの要素を取得
idがafterの要素を取得
before_numの初期値を0
after_numの初期値を0

beforeがクリックされたらbefore_clickedを実行する
afterがクリックされたらafter_clickedを実行する

この機能がやること
before_numに1足す
div要素を作る
その要素のテキストは"前に追加" + before_num
main_divの要素のsub要素の前にdivを挿入する


この機能がやること
after_numに1足す
div要素を作る
その要素のテキストは"前に追加" + after_num
main_divの要素のsub_div要素の後ろにdivを挿入する






HTML Serviceで作ったコードをライブラリ化したい


.gsファイル内でライブラリを使う方法は以下の記事で書きましたが
Google Apps Scriptでライブラリを作って使う

HTML Serviceを利用して作った .htmlファイルを含むスクリプトファイルをライブラリ化したくて試したコードです


ライブラリ側


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

function get_value(){
  var value = "hello";
  return value;
}
意訳
この機能がやること
指定したHTMLファイルを表示する


この機能がやること
helloを
返す




index.html
<!DOCTYPE html>
<html>
<head>

</head>
<body>
  <input type="button" id="bt" value="click me">
  <script>
    var bt = document.getElementById("bt")
    bt.onclick = bt_clicked;

    function bt_clicked() {
      google.script.run
        .withSuccessHandler(success)
        .get_value();
    }

    function success(value) {
      alert(value);
    }
  </script>
</body>
</html>
意訳
  





ボタン

idがbtの要素を取得して
クリックされたらbt_clickedを実行する

この機能がやること
.gsファイルのコードを実行する
成功したらsuccessを実行する
.gsで実行するコードはget_value()


この機能がやること
受け取ったvalueをalertに出す







ライブラリを使う方法はこちら
Google Apps Scriptでライブラリを作って使う


ライブラリを使う側


コード.gs
function doGet(){
  return LIB.doGet();
}

function get_value(){
  return LIB.get_value();
}
意訳
この機能がやること
ライブラリのdoGet()を返す


この機能がやること
ライブラリのget_value()を返す



ライブラリのコードが実行されるので、index.htmlファイルは不要


ウェブアプリケーションとして導入すると
ライブラリ側と同じ結果を返せるようになる


ライブラリを使う側で試したこと


その1

最初はこのコードだけで実現できるかと思い込んでいましたが
function doGet(){
  return LIB.doGet();
}
これだけだと下に書いたようなUncaught TypeErrorが出ました


これを解決するために試したコードを書き残しておきます


ライブラリを使う側の.gs内でライブラリの index.html を表示してみるコード


コード.gs
function doGet(){
  var out = LIB.doGet();
  return ContentService.createTextOutput(out.getContent());
}
意訳
この機能がやること
ライブラリのdoGet()を取得して
内容を表示する




ウェブアプリケーションとして導入すると
ライブラリのindex.htmlの内容が表示されます


その2



コード.gs
function doGet(){
  var out = LIB.doGet();
  return HtmlService.createHtmlOutput(out.getContent())
}

意訳
この機能がやること
ライブラリのdoGet()を取得して
その内容からHTMLを作って返す




これでもHTMLは表示されますが、ボタンを押すと
以下のエラーがconsoleに出力されます
Uncaught TypeError: google.script.run.withSuccessHandler(...).get_value is not a function
    at HTMLInputElement.bt_clicked (<anonymous>:8:10)


get_value()が定義されていないので
↓このコードを追加してやるとエラーが解消されます
function get_value() {
  return "hello";
}


そしてget_value()はライブラリに定義されているので
↓このように書き換えられます
function get_value(){
  return LIB.get_value();
}

さらに function doGet(){} の中もライブラリで定義されているdoGet()を返せば良いので
function doGet(){
  return LIB.doGet();
}
というように書き換えたのが
上で書いた「ライブラリを使う側」のコードです



Wednesday, March 28, 2018

google.script.runの.withUserObject()で第2引数を渡してみる


.withUserObject()に渡した引数はサーバに送られず
成功/失敗の第2引数に渡されるようなので
リファレンスのコードを改造して this と 文字列を渡して試した


以下のようなボタンをクリックした時


そのボタンのvalueに.gsのコードからの戻り値と渡された文字列を入れる

というコードです


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




index.html
<!DOCTYPE html>
<html>
<body>
  <input type="button" id="bt" value="click me">
  <script>
    var bt = document.getElementById("bt")
    bt.onclick = bt_clicked;

    function bt_clicked() {
      google.script.run
        .withSuccessHandler(updateButton)
        .withUserObject([this, "world"])
        .get_value();
    }

    function updateButton(value, array) {
      array[0].value = value + " " + array[1];
    }
  </script>
</body>
</html>
意訳
  


ボタン

idがbtの要素を取得して
クリックされたらbt_clickedを実行する

この機能がやること
.gsファイルのコードを実行する
成功したらonSuccessを実行する
サーバには送らずに第2引数で渡す
.gsで実行するコードはget_value()


この機能がやること
arrayの0番目はthisが渡されているので押されたボタン自身で、そのボタンのvalueにget_value()の戻り値  + " " + arrayの1番目である worldを入れる






参考

Class google.script.run (Client-side API)
https://developers.google.com/apps-script/guides/html/reference/run

Tuesday, March 27, 2018

Array.concatで配列を結合する


このような二次元配列があって
[["あいうえお", "かきくけこ"],["さしすせそ", "たちつてと"],["なにぬねの", "はひふへほ"]]


このように1次元配列にまとめたい
 [あいうえお, かきくけこ, さしすせそ, たちつてと, なにぬねの, はひふへほ]


Array.prototype.push.applyを使う場合は




コード.gs
function array_concat(){
  var array = [["あいうえお", "かきくけこ"],["さしすせそ", "たちつてと"],["なにぬねの", "はひふへほ"]];
  for(var i = 1; i < array.length; i++){
    array[0] = array[0].concat(array[i]);
  }
  Logger.log(array[0]);
}
意訳
この機能がやること
2次元配列を用意して
その中の一次元配列の数だけ以下を繰り返す
0番目の一次元配列に1番目以降の一次元配列をつなげて

出来上がったarray[0]をログに出す



実行結果


その2


このような配列があって
  var array1 = [{en: "english"}, {ja: "japanese"}];
  var array2 = [{fr: "french"}, {it: "italian"}];
  var array3 = [{ko: "korean"}, {de: "Deutschland"}];


このようにひとつにまとめたい
 [[{"en":"english"},{"ja":"japanese"},{"fr":"french"},{"it":"italian"},{"ko":"korean"},{"de":"Deutschland"}]


以下のコードと似ていますが
Array.prototype.push.applyで配列を結合する
array4がマージ前のarray1を返すところが異なります



コード.gs
function array_concat(){
  var array1 = [{en: "english"}, {ja: "japanese"}];
  var array2 = [{fr: "french"}, {it: "italian"}];
  var array3 = [{ko: "korean"}, {de: "Deutschland"}];
  var array4 = array1;
  var array1 = array1.concat(array2) 
                  .concat(array3);
  Logger.log([JSON.stringify(array1), JSON.stringify(array2), JSON.stringify(array3), JSON.stringify(array4)]);
}
意訳
この機能がやること
1つめの配列
2つめの配列
3つめの配列
array4にarray1を入れる
array1にarray2を追加
さらにarray3を追加
それぞれをログに出す



補足


実行結果を見るとこのようなログが出ます

array1,2,3,4を分けてみてみると
array4はマージ前のarray1の配列を返している


array1
[[{"en":"english"},{"ja":"japanese"},{"fr":"french"},{"it":"italian"},{"ko":"korean"},{"de":"Deutschland"}],

array2
[{"fr":"french"},{"it":"italian"}],

array3
[{"ko":"korean"},{"de":"Deutschland"}],

array4
[{"en":"english"},{"ja":"japanese"}]]


スクリプトファイルをコピーして指定したフォルダに入れる


以前このブログで
Googleドライブのファイルをコピーして指定フォルダに入れる
というコードを書きましたが

それと同じことをスクリプトファイルのIDを渡してやろうとしたら
フォルダを指定しているのにマイドライブにコピーファイルが保存されてしまった

同じコードでスプレッドシートのIDを渡すと指定したフォルダにコピーされるので
コードはきっと間違っていない(はず)


何を言っているのかわからない場合はきっとこのコードは役に立ちません。。


今回ぶつかった壁の回避策として以下の手順で代替するコードを書きました
  1. コピーを作る
  2. 指定したフォルダにaddする
  3. 元のファイルをremoveする



コード.gs
var FILE_ID = "ID";
var COPY_FOLDER_ID = "ID";

function copy_file_to_folder() {
  var file = DriveApp.getFileById(FILE_ID);
  var copy_file = make_copy_to_mydrive(file);
  remove_file(copy_file.getId(), COPY_FOLDER_ID);
}

function make_copy_to_mydrive(file) {
  var copy_file_name = "Copy of " + file.getName() + format_date();
  var copy_file = file.makeCopy(copy_file_name);
  return copy_file;
}

function remove_file(file_id, folder_id){
  var target_folder = DriveApp.getFolderById(folder_id);
  var file = DriveApp.getFileById(file_id);
  var parent_folder = file.getParents().next();
  target_folder.addFile(file);
  parent_folder.removeFile(file);
}

function format_date(){
  var date = new Date();
  var formated = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd/HH:mm:ss:sss');
  return formated;
}
意訳
ファイルのID
コピー先のフォルダのID

この機能がやること
オリジナルのファイルを取得して
マイドライブにコピーを作成して
コピーしたファイルを指定したフォルダに移動する


この機能がやること
コピーファイルの名前を決めて
マイドライブにファイルをコピーして(フォルダを指定しないとマイドライブになる)
コピーしたファイルを返す


この機能がやること
コピー先のフォルダを取得して(受け取ったIDから取得)
受け取ったファイルID(コピーしたファイル)を取得して
ファイルの親フォルダを取得して
コピー先のフォルダにファイルを追加して
親フォルダの中からファイルを削除する


この機能がやること
現在日時を取得して
フォーマットして
返す




ちなみにマイドライブにコピーする場合は

コード.gs
var FILE_ID = "ID";
function copy_file_to_mydrive() {
  var file = DriveApp.getFileById(FILE_ID);
  var name = "Copy of " + file.getName();
  file.makeCopy(name);
}



参考

removeFile(child)
https://developers.google.com/apps-script/reference/drive/drive-app#removeFile(File)

Array.prototype.push.applyで配列を結合する(2次元配列を1次元配列にしたい)


このような2次元配列があって

[["あいうえお", "かきくけこ"],["さしすせそ", "たちつてと"],["なにぬねの", "はひふへほ"]];


このように1次元配列にまとめたい
[あいうえお, かきくけこ, さしすせそ, たちつてと, なにぬねの, はひふへほ]


Array.concatを使う場合は



コード.gs
function array_push_apply(){
  var array = [["あいうえお", "かきくけこ"],["さしすせそ", "たちつてと"],["なにぬねの", "はひふへほ"]];
  for(var i = 1; i < array.length; i++){
    Array.prototype.push.apply(array[0], array[i]);
  }
  Logger.log(array[0]);
}
意訳
この機能がやること
2次元配列を用意して
その中の1次元配列の数だけ以下を繰り返す
arrayの0番目に1番目以降を追加していく

すべてが追加されたarray[0]をログに出す



実行結果


その2


このような配列があって
  var array1 = [{en: "english"}, {ja: "japanese"}];
  var array2 = [{fr: "french"}, {it: "italian"}];
  var array3 = [{ko: "korean"}, {de: "Deutschland"}];


このようにひとつにまとめたい
 [[{"en":"english"},{"ja":"japanese"},{"fr":"french"},{"it":"italian"},{"ko":"korean"},{"de":"Deutschland"}]



コード.gs
function array_push_apply(){
  var array1 = [{en: "english"}, {ja: "japanese"}];
  var array2 = [{fr: "french"}, {it: "italian"}];
  var array3 = [{ko: "korean"}, {de: "Deutschland"}];
  var array4 = array1;
  Array.prototype.push.apply(array1, array2);
  Array.prototype.push.apply(array1, array3);
  Logger.log([JSON.stringify(array1), JSON.stringify(array2), JSON.stringify(array3), JSON.stringify(array4)]);
}
意訳
この機能がやること
1つめの配列
2つめの配列
3つめの配列
array4にarray1を入れる
array1にarray2を追加
array1にarray3を追加
それぞれをログに出す



補足


実行結果を見るとこのようなログが出ます

array1,2,3,4を分けてみてみると
array4もマージされた配列を返している


array1
[[{"en":"english"},{"ja":"japanese"},{"en":"english"},{"ja":"japanese"},{"fr":"french"},{"it":"italian"},{"ko":"korean"},{"de":"Deutschland"}],

array2
[{"fr":"french"},{"it":"italian"}],

array3
[{"ko":"korean"},{"de":"Deutschland"}],

array4
[{"en":"english"},{"ja":"japanese"},{"en":"english"},{"ja":"japanese"},{"fr":"french"},{"it":"italian"},{"ko":"korean"},{"de":"Deutschland"}]]



複数のオブジェクトをObject.assignでマージする


このようなオブジェクトがあって
  var obj1 = {en: "english", ja: "japanese"};
  var obj2 = {fr: "french", it: "italian"};
  var obj3 = {ko: "korean", de: "deutschland"};


このようにひとつにまとめたい
{"en":"english","ja":"japanese","fr":"french","it":"italian","ko":"korean","de":
"deutschland"}


.gsファイル内ではエラーが出て使えませんが、HTML ServiceのJavaScriptでは使えたため備忘録として


.gsファイル内で使うときに出るエラー
TypeError: オブジェクト function Object() { [native code for Object.Object, arity=1] } で関数 assign が見つかりません。



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




index.html
<!DOCTYPE html>
<html>
<body>
  <script>
    obj_assign();
    function obj_assign() {
      var obj1 = {
        en: "english",
        ja: "japanese"
      };
      var obj2 = {
        fr: "french",
        it: "italian"
      };
      var obj3 = {
        ko: "korean",
        de: "deutschland"
      };
      var obj = Object.assign(obj1, obj2, obj3);
      alert([JSON.stringify(obj), JSON.stringify(obj1), JSON.stringify(obj2), JSON.stringify(obj3)]);
    }
  </script>
</body>
</html>
意訳
  



obj_assign()を実行する
この機能がやること
1つめのオブジェクト



2つめのオブジェクト



3つめのオブジェクト



obj1にobj2とobj3をマージして
obj, obj1, obj2, obj3の中身をアラートに出す






Google Apps ScriptのJavaScriptのバージョン


2020-02-05までは、baseにしているJavaScriptのバージョンは 1.6 でしたが
アップデートがあって、アロー関数なども使えるようになった。

Release Notes
https://developers.google.com/apps-script/releases#february_5_2020


Built-in Google Services からの 引用
Modern JavaScript features
Apps Script supports two JavaScript runtimes: the modern V8 runtime and an older one powered by Mozilla's Rhino JavaScript interpreter.

The V8 runtime supports modern ECMAScript syntax and features. The Rhino runtime is based on the older JavaScript 1.6 standard, plus a few features from 1.7 and 1.8. You can freely choose which runtime to use with your script, but the V8 runtime is strongly recommended.


Sunday, March 25, 2018

スプレッドシートのセルにノートを入力する


ノートとは
  • セルにメモを残せる
  • 入力されているとセルの右上に黒い三角マークが出る
  • ポインターを合わせると入力されたテキストが表示される


メニューからノートを入力する場合は
挿入 > メモ
から入力できる



コード.gs
var ss_url = 'Spreadsheet_URL';

function setNote() {
  var ss = SpreadsheetApp.openByUrl(ss_url);
  var sh_id = 0;
  var sheet = get_sheet(ss, sh_id);
  var range = sheet.getRange("A1");
  value = "NOTE_A1"
  range.setNote(value);
}

function setNotes() {
  var ss = SpreadsheetApp.openByUrl(ss_url);
  var sh_id = 0;
  var sheet = get_sheet(ss, sh_id);
  var range = sheet.getRange("A1:B2");  
  var values = [
    ["NOTE_A1", "NOTE_B1"],
    ["NOTE_A2", "NOTE_B2"]
  ];
  range.setNotes(values);
}

function get_sheet(ss, sh_id) {
  var shs = ss.getSheets();
  for (var i = 0; i < shs.length; i++) {
    if (shs[i].getSheetId() == sh_id) {
      break;
    }
  }
  var sh = ss.getSheets()[i];
  return sh;
}
意訳
スプレッドシートのURL

この機能がやること
スプレッドシートを開く
シートのidを決めて
ss_urlとsh_idを渡して対象のシートを取得する
A1を取得して
入力する値を決めて
ノートに入力する


この機能がやること
スプレッドシートを開く
シートのidを決めて
ss_urlとsh_idを渡して対象のシートを取得する
入力する範囲を取得して
入力する値を決めて
A1のノートの値, B1のノートの値, 
A2のノートの値, B2のノートの値

それぞれのノートに値を入力する


この機能がやること
対象のスプレッドシートのシートをすべて取得して
シートの数だけ以下を繰り返す
シートのidがsh_idなら
for文から抜ける


スプレッドシートでシートをを見つけて
返す



setNote()を実行するとA1にノートが入力されます

setNotes()を実行するとA1:B2にノートが入力されます


Wednesday, March 21, 2018

文字をUTF16と16進数の数値に変換する


テキスト入力欄に文字を入力するとUTF16と16進数欄にそれぞれの数値が入ります







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




index.html
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
  <style>
    .card {
      width: 360px;
      padding: 15px;
      border-radius: 2px;
      border: solid 1px lightgray;
      box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
    }

    textarea,
    input[type='text'] {
      width: 95%;
      font-size: 15px;
      margin: 5px;
    }
  </style>
</head>
<body>
  <div class='card'>
    <p>
      <label>テキスト入力欄</label>
      <input type='text' id='keywords' class='text_midium'>
    </p>
    <p>
      <label>UTF16</label>
      <textarea id='ta'></textarea>
    </p>
    <p>
      <label>16進数</label>
      <textarea id='ta2'></textarea>
    </p>
  </div>
  <script>
    var keywords = document.getElementById('keywords')
    var ta = document.getElementById('ta')
    var ta2 = document.getElementById('ta2')

    keywords.focus()
    keywords.onkeyup = split_text

    function split_text() {
      var str = keywords.value
      var utf16 = []
      var hexadecimal = []
      for (var i = 0; i < str.length; i++) {
        utf16.push(str.charCodeAt(i))
        hexadecimal.push(utf16[i].toString(16));
      }
      ta.value = utf16
      ta2.value = hexadecimal
    }
  </script>
</body>
</html>
意訳
  




cardのスタイル
幅
内側の余白
角丸
枠線
影


textareaと
input type='text'のスタイル
幅
文字の起きさ
外側の余白






文字入力欄



UTF16の結果を入れる欄



16進数の結果を入れる欄




idがkeywordsの要素を取得
idがtaの要素を取得
idがta2の要素を取得

文字の入力欄をフォーカスする
文字が入力されたらsplit_textを実行する

この機能がやること
入力された文字を取得する
utf16の結果を入れる配列を用意する
16進数の結果を入れる配列を用意する
入力された文字の数だけ以下を繰り返す
UTF16の値を表す数値を配列に追加する
16進数を配列に追加する

taにresultを入れる
ta2にresult2を入れる







漢字、ひらがな、カタカナ、英数字を正規表現で区切る


入力した文字列から
指定したパターンに一致した文字と
一致しなかった文字を取得してみる

ということをやりたくて正規表現を使って書いてみた例です

今回書いたコードで使っている正規表現
漢字、ひらがな、カタカナ、半角カタカナ、半角英数、全角英数で区切りたくて
このように書いています

/[々〆〇〻㐂-頻]+|[ぁ-ゟー]+|[゠-ヿ]+|[ヲ-゚]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+/g



テキスト入力欄にテキストを入力すると
正規表現で指定したパターンを元に
漢字、ひらがな、カタカナ、英数字、それ以外で分割されて
一致したテキストと一致しなかったテキストで分割される



デモ








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




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .card {
      width: 360px;
      padding: 15px;
      border-radius: 2px;
      border: solid 1px lightgray;
      box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
    }

    .center {
      text-align: center;
    }

    textarea,
    input[type='text'] {
      width: 95%;
      font-size: 15px;
      margin: 5px;
    }
  </style>
</head>
<body>
  <div class='card'>
    <p>
      <label>テキスト入力欄</label>
      <input type='text' id='keywords' class='text_midium'>
    </p>
    <p>
      <label>漢字、ひらがな、カタカナ、英数字に一致</label>
      <textarea id='ta'></textarea>
    </p>
    <p>
      <label>一致しない文字</label>
      <textarea id='ta2'></textarea>
    </p>
  </div>
  <script>
    var keywords = document.getElementById('keywords')
    var ta = document.getElementById('ta')
    var ta2 = document.getElementById('ta2')

    keywords.focus()
    keywords.onkeyup = split_text

    function split_text() {
      var str = keywords.value
      var pattern = /[々〆〇〻㐂-頻]+|[ぁ-ゟー]+|[゠-ヿ]+|[ヲ-゚]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+/g
      var pattern2 = /[^々〆〇〻㐂-頻ぁ-ゟー゠-ヿヲ-゚a-zA-Z0-9a-zA-Z0-9]/g
      var result = str.match(pattern)
      var result2 = str.match(pattern2)
      ta.value = result
      ta2.value = result2
    }
  </script>
</body>
</html>
意訳
  



cardのスタイル
幅
内側の余白
角丸
枠線
影


centerのスタイル
水平方向の位置


textareaと
input type='text'のスタイル
幅
文字の起きさ
外側の余白






テキスト入力欄




一致した文字の結果を入れる欄



一致しなかった文字を入れる欄



idがkeywordsの要素を取得
idがtaの要素を取得
idがta2の要素を取得

文字の入力欄をフォーカスする
文字が入力されたらsplit_textを実行する

この機能がやること
入力された文字を取得する
漢字、ひらがな、カタカナ、半角カタカナ、半角英数字、全角英数字に一致するそれぞれの正規表現
一致しない正規表現
入力された文字からpatternに一致するものを抜き出す
一致しない者を抜き出す
taにresultを入れる
ta2にresult2を入れる








補足


Apps ScriptのHTML Serviceではindex.htmlのコードで問題なく動きました

しかし、このブログで利用しているBloggerのHTMLにJavaScriptを書いて試してみると意図したとおりに分割できませんでした


以下のように「、」も一致してしまう

これを解消するために
patternとpattern2をconsole.logで出力してみるとこうなっていました
〇 が &#12295;
゠ が &#12448;
になっている


このままでは使えないのでそれぞれを16進数にしてみる

〇 を \u3007
゠ を \u30a0
にして以下のようにpatternとpattern2のコードを置き換えてみるとうまくいきました

var pattern = /[々〆\u3007〻㐂-頻]+|[ぁ-ゟー]+|[\u30a0-ヿ]+|[ヲ-゚]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+/g
var pattern2 = /[^々〆\u3007〻㐂-頻ぁ-ゟー\u30a0-ヿヲ-゚a-zA-Z0-9a-zA-Z0-9]/g

文字をUTF16にして16進数にしてシートに書き出す


A列にこのように文字が入っていて


UTF16に変換してB列に入力して
16進数に変換してC列に入力する



コード.gs
function str_utf16_hexadecimal() {
  var values = get_values();
  var result = [];
  for(var i = 0; i < values.length; i++){
    var str = values[i].toString()
    var utf16 = get_utf16(str);
    var hexdecimal = get_hexdecimal(utf16);
    result.push([utf16, hexdecimal]);
  }
  set_values(result);
}

function get_values(){
  var sh = SpreadsheetApp.getActiveSheet();
  var last_row = sh.getLastRow();
  var range = sh.getRange("A2:A" + last_row);
  var values = range.getValues();
  return values;
}

function get_utf16(str) {
  var array = [];
  var low = "";
  if (str.length == 2) {
    var high = str.charCodeAt(0);
    var low = str.charCodeAt(1);
    var utf16 = high + " " + low;
  } else {//サロゲートペア以外なら
    var utf16 = str.charCodeAt(0);
  }
  array.push(utf16);
  return array;
}

function get_hexdecimal(utf16) {
  var surrogates = false;
  var hexdecimal = "";
  var str_split = utf16.toString().split(" ");
  if (str_split.length == 2) {
    surrogates = true;
  }
  if (surrogates == true) {
    var high = "0x" + parseInt(str_split[0]).toString(16);
    var low = "0x" + parseInt(str_split[1]).toString(16);
    hexdecimal = high + " " + low;
  } else {
    hexdecimal = "0x" + parseInt(utf16).toString(16);
  }
  return hexdecimal;
}

function set_values(array){
  var sh = SpreadsheetApp.getActiveSheet();
  var start_row = 2;
  var start_col = 2;
  var num_rows = array.length;
  var num_cols = array[0].length;
  var range = sh.getRange(start_row, start_col, num_rows, num_cols);
  range.setValues(array); 
}

意訳
この機能がやること
get_values()から値を取得して
結果を入れる配列を用意して
値の数だけ以下を繰り返す
値をひとつずつ文字列にして
get_utf16(str)に渡して
get_hexdecimal(utf16)に渡して
resultに追加する

resultをset_values()に渡す


この機能がやること
アクティブシートを取得して
データが入っている最終行を取得して
A2から最終行までを範囲指定して
値をすべて取得して
返す


この機能がやること
結果を入れる配列を用意して
サロゲートペアの後半を入れる入れ物を用意して
もし渡された文字がサロゲートペアなら
前半部分をUTF16にして
後半部分をUTF16にして
前後半を半角スペース入れてつなげる
サロゲートペア以外なら
渡された文字をUTF16にして

UTF16の値をarrayに追加して
返す


この機能がやること
サロゲートペアのフラグをfalseにしておく
16進数の結果を空にしておく
渡されたutf16を文字列にして半角スペースで区切る
もし2つ以上(サロゲートペア)なら
surrogatesフラグをtrueにする

もしsurrogatesフラグがtrueなら
区切った前半を16進数にして
区切った後半を16進数にして
半角スペースを挟んでつなげる
サロゲートペアじゃなければ
渡されたutf16を16進数にして

16進数の値を返す


この機能がやること
アクティブシートを取得して
入力する先頭の行を指定して
入力する先頭の列を指定して
入力する行数を指定して
入力する列数を指定して
入力する範囲を指定して
入力する




関連記事

文字列をUTF-16に変換する
文字列⇔UTF16⇔16進数の相互変換をする(サロゲートペア非対応)
文字列⇔UTF16⇔16進数の相互変換をする(サロゲートペア対応)
文字列→UTF16→16進数→文字列に変換する

Monday, March 19, 2018

SpreadsheetのQUERY関数でシートを結合する


QUERY関数で2つのシートを結合する(範囲固定)


=QUERY({'対象シート'!範囲;'対象シート'!範囲})


=QUERY({'シート1'!A1:A4;'シート2'!A2:A4})


1. シート1にこういうデータがあり


2. シート2にこういうデータがあり


3. 上記2つのシートのデータをシート3で結合してみる
=QUERY({'シート1'!A1:A4;'シート2'!A2:A4})



QUERY関数で複数列のデータを一列にまとめる


=QUERY({
QUERY(A2:C,"select A,B");
QUERY(A2:C,"select A,C")},
"where Col1 is not null order by Col1")




異なるシートのデータを読み込んで結合する
(QUERY関数、IMPORTRANGE関数)

(スプレッドシートのURLとシート名はご自身のものに置き換えてください)

=query({query(importrange("https://docs.google.com/spreadsheets/d/1i2rtZUstp40O_FjxX3H9X2_hr8WnpyFnKgN0VP0uTzk/edit#gid=0", "シート1!A1:C"),"select Col1"), 

query(importrange("https://docs.google.com/spreadsheets/d/1i2rtZUstp40O_FjxX3H9X2_hr8WnpyFnKgN0VP0uTzk/edit#gid=0", "シート1!A1:C"),"select Col2")})





一列にまとめる

=query({
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C"), "select Col1,Col2");
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C"), "select Col1,Col3")
},"where Col1 is not null order by Col1")


異なるスプレッドシートのデータを1つのシートにまとめる


=query({
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C"));
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=523722773", "シート4!A2:C"))
},"where Col1 is not null order by Col1")


このシートのA2:Cの範囲
importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C")

このシートのA2:Cの範囲
https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=523722773", "シート4!A2:C")


上記2つのシートで指定した範囲を別のシートで結合する
=query({
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C"));
query(importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=523722773", "シート4!A2:C"))
},"where Col1 is not null order by Col1")


補足
#REF! が出る場合
query関数でまとめる前に importrange関数 だけで読み込んで
「アクセスを許可」してみるとうまくいくかも


こんな感じで試してみる
=importrange("https://docs.google.com/spreadsheets/d/1-U1VYQUofqQO9dY0WyHls4KwuZxJUpu3iw74eeQCTU0/edit#gid=0", "シート1!A2:C")


importrange関数で別のシートのデータを読み込む


別のシートのデータを読み込む IMPORTRANGE関数 の備忘録


以下のようにすると読み込める

=importrange("読み込み元のスプレッドシートのURL", "読み込むシートと範囲")


STEP 1


読み込み元のスプレッドシートを用意する


STEP 2


もう一つ別のスプレッドシートを作成してこのシートに読み込む
STEP 1 のURLをコピーして、以下のように読み込むシートと範囲を指定する

=importrange("読み込み元のスプレッドシートのURL", "読み込むシートと範囲")

=importrange("URL", "シート1!A1:A")



「アクセスを許可」をクリックする


STEP 1 のデータが読み込まれる


元のシートを編集すると、その変更も反映される


stickyで画面スクロールしてもついてくる要素を作る


こういう要素を作ってみる

固定要素(スクロールしても上端に固定)
テキスト1
テキスト2
テキスト3
テキスト4
テキスト5
テキスト6
テキスト7
テキスト8
テキスト9
テキスト10
テキスト11
テキスト12




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




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .sticky {
      position: sticky;
      top: 0;
    }

    .height40 {
      height: 40px;
    }

    .height1200 {
      height: 1200px;
    }

    .card {
      width: 360px;
      border: solid 1px lightgray;
      box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
      background: white;
    }
  </style>
</head>
<body>
  <div class="card height40 sticky">固定エリア</div>
  <div class="card height1200">
    <p>テキスト1</p>
    <p>テキスト2</p>
    <p>テキスト3</p>
    <p>テキスト4</p>
    <p>テキスト5</p>
    <p>テキスト6</p>
    <p>テキスト7</p>
    <p>テキスト8</p>
    <p>テキスト9</p>
    <p>テキスト10</p>
    <p>テキスト11</p>
    <p>テキスト12</p>
  </div>
</body>
</html>
意訳
 



stickyのスタイル
画面をスクロールしても↓で設定した位置に固定する
上端からの距離


height40のスタイル
高さ


height1200のスタイル
高さ


cardのスタイル
幅
枠線
影
背景色




固定エリアのdiv
スクロールされるエリアのdiv

















Monday, March 12, 2018

テキストエリアの枠を消したい


border:none と resize:none を使う


枠あり

<textarea>hello</textarea>





枠無し

<textarea style="border:none;">hello</textarea>





枠無し&リサイズなし

<textarea style="border:none;resize:none;">hello</textarea>




参考

resize

Sunday, March 11, 2018

JavaScriptで前後の要素を取得する


前後の要素を取得する場合のコードの例

  • nextElementSibling
  • previousElementSibling




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




index.html
<!DOCTYPE html>
<html>
  <body>
    <p>ひとつめ</p>
    <p id="second">ふたつめ</p>
    <p>みっつめ</p>
  </body>
  <script>
    var second = document.getElementById("second");
    var first = second.previousElementSibling.textContent;
    var third = second.nextElementSibling.textContent;
    alert([first, third])
  </script>
</html>
意訳
  


ひとつめのp要素
ふたつめのp要素
みっつめのp要素


idがsecondの要素を取得
secondの前の要素のテキストを取得
secondの後の要素のテキストを取得
アラートに出す




formの入力欄を必須にするrequired


formの項目を必須入力にしたくて調べた時の備忘録


項目にrequireをつける
<input type="text" required>



index.html
<!DOCTYPE html>
<html>
<body>
  <form>
    <input type="text" required>
    <button type="submit">button</button>
  </form>
</body>
</html>


formのsubmitをfalseにする


formのonsubmitを無効にしたくて調べた時の備忘録


これで無効にできる
<form onsubmit="return false">



index.html
<!DOCTYPE html>
<html>
<body>
  <form onsubmit="return false">
    <input type="text">
    <button type="submit">button</button>
  </form>
</body>
</html>


ヘッダ付きのカードを動的に作る


CSSでカードのヘッダを作りたい で作ったヘッダ付きのカードをJavaScriptで作ってみる




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




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .card {
      width: 360px;
      min-height: 240px;
      border-radius: 3px;
      border: solid 1px lightgray;
      box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
      margin-bottom: 20px;
      margin-right: 20px;
    }

    .card_header {
      color: white;
      font-weight: bold;
      background-color: deepskyblue;
      padding: 15px;
      border-radius: 3px 3px 0px 0px
    }

    .card_content {
      padding: 15px;
    }
  </style>
</head>
<body>
  <div id="main_div"></div>

  <script>
    document.addEventListener('DOMContentLoaded', create_card());

    function create_card() {
      var parent_div = document.getElementById("main_div");
      var card_div = create_card_div(parent_div);
      var card_header = create_card_header(card_div);
      var card_content = create_card_content(card_div);
    }

    function create_card_div(parent_div) {
      var card_div = document.createElement("div");
      card_div.setAttribute("class", "card");
      parent_div.appendChild(card_div);
      return card_div;
    }

    function create_card_header(card_div) {
      var card_header = document.createElement("div");
      card_header.setAttribute("class", "card_header");
      card_header.textContent = "header";
      card_div.appendChild(card_header);
    }

    function create_card_content(card_div) {
      var card_content = document.createElement("div");
      card_content.setAttribute("class", "card_content");
      card_content.textContent = "content";
      card_div.appendChild(card_content);
    }
  </script>
</body>
</html>


Saturday, March 10, 2018

getComputedStyleでスタイルを取得する


要素のスタイルを取得する時に class で設定したスタイルは element.style では取得できず、getComputedStyleで取得できることを知った時の備忘録です


styleとclassで取得方法は異なる
  • style="color:green;" のようにstyleで設定されている場合
    • elem.style.color
    • などで各プロパティ(colorとかwidthとか)の値を取得できる
    • elem.style.color = "yellow" で値を上書きできる

  • class="div1_class" のようにclassで設定されている場合
    • elem.style.color
    • では取得できない
    • window.getComputedStyle(要素, 擬似要素)
    • で各プロパティの値を取得できる
    • 取得するだけで値の変更はできない



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




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .div1_class {
      color: blue;
    }
  </style>
</head>
<body>
  <div id="div1" class="div1_class">div1</div>
  <div id="div2" style="color:green;">div2</div>
  <textarea id="ta" style="width:240px;height:240px;"></textarea>
  <br>
  <button id="bt">button</button>
  <script>
    var div1 = document.getElementById("div1");
    var div2 = document.getElementById("div2");
    var ta = document.getElementById("ta");
    var bt = document.getElementById("bt");
    bt.onclick = bt_clicked;

    var div1_style = window.getComputedStyle(div1, null);
    var div2_style = div2.style;

    function bt_clicked() {
      var way1 = div1_style.color;
      var way2 = div1_style.getPropertyValue("color");
      var way3 = div1.style.color;
      var way4 = div2_style.color;
      var result = [way1, way2, way3,  way4, JSON.stringify(div1_style)];
      ta.value = result
    }
  </script>
</body>
</html>
意訳
 



div1_classのスタイル
文字色




div1
div2
textarea

button

idがdiv1の要素を取得
idがdiv2の要素を取得
idがtaの要素を取得
idがbtの要素を取得
btがクリックされたらbt_clickedを実行する

div1でwindow.getComputedStyleを取得する
div2でstyleを取得する

この機能がやること
colorを取得する一つ目の方法
colorを取得する二つ目の方法
colorを取得する三つ目の方法
colorを取得する四つ目の方法
取得した4つの値とdiv1_styleをJSONにした結果を配列にして
taに入れる







buttonをクリックすると以下のような結果が出力されます


補足


way1, way2, way3,  way4

の結果は

rgb(0, 0, 255),rgb(0, 0, 255),,green


way1:window.getComputedStyle(div1, null).color
way2:window.getComputedStyle(div1, null).getPropertyValue("color")
の結果は<style></style>の中で設定されている blue をRGBで表した rgb(0, 0, 255) が返ってくる

way3:document.getElementById("div1").color
はタグ内で style が設定されていないので取得できない

way4:document.getElementById("div2").color
はタグ内で style="color:green" で設定された green が返ってくる


関連記事

スタイルを上書きしたい場合



参考

JavaScript Window getComputedStyle() Method
https://www.w3schools.com/jsref/jsref_getcomputedstyle.asp

window.getComputedStyle
https://developer.mozilla.org/ja/docs/Web/API/Window/getComputedStyle

div要素の中でセンタリングしたい(垂直水平方向の配置)


div要素の中で子要素をセンタリングしたくていくつか試したので書き残しておきます


display: table-cellを使った垂直水平方向のセンタリング

middle center

.middle_center {
  display: table-cell;
  width: 120px;
  height: 120px;
  border: solid 1px lightgray;
  vertical-align: middle;
  text-align: center;
}

<div class="middle_center">
  middle center
</div>



上記のセンタリングを実現する過程で試した垂直水平方向の配置
(paddingを使う方法も)
  • display
    • table-cell
  • vertical-align
    • top
    • middle
    • bottom
  • text-align
    • center
    • right
    • left
  • padding


垂直水平方向の配置を設定する




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




index.html
<!DOCTYPE html>
<html>
<head>
  <style>
    .middle_center {
      display: table-cell;
      width: 120px;
      height: 120px;
      border: solid 1px lightgray;
      vertical-align: middle;
      text-align: center;
    }
  
    .table {
      display: table-cell;
      width: 120px;
      height: 120px;
      border: solid 1px lightgray;
    }

    .vertical_top {
      vertical-align: top;
    }

    .vertical_middle {
      vertical-align: middle;
    }

    .vertical_bottom {
      vertical-align: bottom;
    }

    .text_center {
      text-align: center;
    }

    .text_right {
      text-align: right;
    }

    .text_left {
      text-align: left;
    }

    .center {
      vertical-align: middle;
      text-align: center;
    }

    .center_padding {
      width: 120px;
      padding: 40px 0;
      border: 1px solid lightgray;
      text-align: center;
    }
  </style>
</head>

<body>
  水平垂直の中央
  <div class="middle_center">
    middle center
  </div>
  <br>

  vertical-align 垂直の位置
  <div class="table vertical_top">
    top
  </div>

  <div class="table vertical_middle">
    middle
  </div>

  <div class="table vertical_bottom">
    bottom
  </div>

  <br>
  text-align 水平の位置
  <div class="table text_center">
    center
  </div>

  <div class="table text_right">
    right
  </div>

  <div class="table text_left">
    left
  </div>

  <br>
  padding 内部の余白
  <div class="center_padding">
    padding center
  </div>
</body>
</html>
意訳
 



middle_centerのスタイル
table-cellで表示する
幅
高さ
枠線
垂直方向の中段に配置
水平方向の中央に配置


tableのスタイル
table-cellで表示する
幅
高さ
枠線


vertical_topのスタイル
垂直方向の上段に配置


vertical_middleのスタイル
垂直方向の中段に配置


vertical_bottomのスタイル
垂直方向の下段に配置


text_centerのスタイル
水平方向の中央に配置


text_rightのスタイル
水平方向の右端に配置


text_leftのスタイル
水平方向の左端に配置


centerのスタイル
セルの中段に配置
水平方向の中央に配置


center_padding
幅
高さ
枠線
水平方向の中央に配置






div要素にtableとvertical_topのスタイルを設定





div要素にtableとvertical_middleのスタイルを設定



div要素にtableとvertical_bottomのスタイルを設定



div要素にtableとtext_centerのスタイルを設定





div要素にtableとtext_rightのスタイルを設定



div要素にtableとtext_leftのスタイルを設定



div要素にtableとcenterのスタイルを設定





div要素にcenter_paddingのスタイルを設定






Latest post

Extracting data from Google Sheets with regular expressions

Introduction Regular expressions are a powerful tool that can be used to extract data from text.  In Google Sheets, regular expressions ca...