I share this blog with my thoughts and creations from my daily programming, knowledge, and technology updates.
Apps Scriptリファレンス: Apps Script Reference
|障害・課題追跡: IssueTracker
|Google Workspace: Status Dashboard
- Summary
2018年5月31日木曜日
気になった設定やぶつかった壁の越え方を書き残して行くページ
題名の通り個人的な備忘録
+同じ壁にぶつかっている人の役に立つかも
Google フォトと Google ドライブの連携
デスクトップ > Google ドライブ > 設定 > 「Google フォト」フォルダを作成する] をクリック
Android端末 > Google フォト > 設定 > バックアップと同期 > モバイル通信でのバックアップ > 写真をON
ダウンロードを保留しています(Android Google Play)
アップデート保留中で更新中のアプリがあるのが原因の場合
Android端末 > Google Playホーム画面の左上の三本線メニュー > マイアプリ&ゲーム > アップデート
→アップデート保留中の右にある「停止」ボタンをクリックして一度停止する
→ダウンロードしたいアプリを再度ダウンロードしてみる
2018年5月27日日曜日
opacityで要素を透明にする
要素をこのように半透明にしてみる
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <head> <style> .opacity_05 { opacity: 0.5; } </style> </head> <body> <button>通常ボタン</button> <button class="opacity_05">半透明ボタン</button> </body> </html> |
意訳opacity_05のスタイル 半透明にする 通常ボタン 半透明ボタン |
classListでスタイルをadd, remove, toggle, containsする
classListで要素のスタイルを操作してみる
デモ
(Apps ScriptのWebアプリで作ったもの)
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <head> <style> .bg_pink { background-color: pink; } </style> </head> <body> <textarea id="ta"></textarea><br> <button id="add_bt">add</button> <button id="remove_bt">remove</button> <button id="toggle_bt">toggle</button> <button id="contains_bt">contains</button> <script> document.getElementById("add_bt").onclick = add_bt_clicked; document.getElementById("remove_bt").onclick = remove_bt_clicked; document.getElementById("toggle_bt").onclick = toggle_bt_clicked; document.getElementById("contains_bt").onclick = contains_bt_clicked; var ta = document.getElementById("ta"); function add_bt_clicked(){ ta.classList.add("bg_pink"); } function remove_bt_clicked(){ ta.classList.remove("bg_pink"); } function toggle_bt_clicked(){ ta.classList.toggle("bg_pink"); } function contains_bt_clicked(){ ta.value = ta.classList.contains("bg_pink"); } </script> </body> </html> |
意訳bg_pinkのスタイル 背景色をpinkにする テキストエリア addボタン removeボタン toggleボタン containsボタン addボタンをクリックしたらadd_bt_clickedを実行する removeボタンをクリックしたらremove_bt_clickedを実行する toggleボタンをクリックしたらtoggle_bt_clickedを実行する containsボタンをクリックしたらcontains_bt_clickedを実行する idがtaの要素を取得する この機能がやること idがtaのテキストエリアにbg_pinkのスタイルを追加する この機能がやること idがtaのテキストエリアからbg_pinkのスタイルを削除する この機能がやること idがtaのテキストエリアにbg_pinkのスタイルがなければaddしてあればremoveする この機能がやること idがtaのテキストエリアにbg_pinkのスタイルがあればtrueしてなければfalseを返す |
2018年5月26日土曜日
指定した要素の子要素の最後の要素を取得したい
- elem.childrenで指定した要素の子要素を取得
- elem.children.lengthでその数を取得
- elem.children[len - 1]でその最後の要素を取得
という感じでinnerHTMLまで取得してみる
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <body> <div id="main_div"> <div>あめ</div> <div>ちょこ</div> <div>がむ</div> </div> </body> <script> get_last_elem("main_div") function get_last_elem(id){ var elem = document.getElementById(id); var len = elem.children.length; var last_elem = elem.children[len - 1]; alert(last_elem.innerHTML); } </script> </html> |
意訳main_divの要素 あめ div ちょこ div がむ div get_last_elem()でmain_divの最後の要素を取得する この機能がやること 受け取ったidから一致する要素を取得して その要素の子要素の数を取得して その要素の最後の子要素を取得して innerHTMLをアラートに出す |
.getElementsByTagNameで取得する
index.html<!DOCTYPE html> <html> <body> <div id="main_div"> <div>あめ</div> <div>ちょこ</div> <div>がむ</div> </div> </body> <script> get_last_elem("main_div") function get_last_elem(id){ var elem = document.getElementById(id); var divs = elem.getElementsByTagName("div"); var len = divs.length; var last_elem = divs[len - 1]; alert(last_elem.innerHTML); } </script> </html> |
参考
ParentNode.children
https://developer.mozilla.org/ja/docs/Web/API/ParentNode/children
document.getElementsByTagName
https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByTagName
スタイルを複数設定するときの備忘録
今回設定したスタイル
.blue が設定されていたら青文字
.bt が設定されていたら背景色は灰色
.blueか.btどちらかが設定されていたら太文字
.blueと.btの両方が設定されていたら背景色はピンク
.blue.bt
と書くとblueとbtの両方が設定されているときのスタイル
.blue, .bt
と書くとblueまたはbtのどちらかが設定されているときのスタイル(共通のスタイル)
と書くとblueとbtの両方が設定されているときのスタイル
.blue, .bt
と書くとblueまたはbtのどちらかが設定されているときのスタイル(共通のスタイル)
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <head> <style> .blue { color: blue; } .bt { width: 60px; height: 30px; background-color: lightgrey; border: none; } .blue.bt { background-color: lightblue; } .blue, .bt { font-weight: bold; } </style> </head> <body> <label class="blue">ラベル</label> <button class="bt">ボタン</button> <button class="blue bt">ボタン</button> </body> </html> |
意訳blueのスタイル btのスタイル blueとbt両方が設定されているときのスタイル blueとbtに共通のスタイル ラベルにblueのスタイルを設定 ボタンにbtのスタイルを設定 ボタンにblueとbtのスタイルを設定 |
2018年5月25日金曜日
A,B列の値を5行ずつ処理してC列に入れる
良いタイトルが浮かばなかったのでそのままですが
たまにこういう処理をしたくなって。
トリガーに登録したら6分の壁を越える時にも使える。
コード.gs
/************************************ A列とB列のデータをもとに何か処理を施して C列に結果を入れる これを一つずつやるとgetValue()とsetValue()が多すぎてアラートが出る かといって一気にあるだけ全部をgetLastRow()とgetValues()で取得してsetValues()でやるには多すぎたり そんなときにとりあえず5行ずつやってみようというコード この例ではA列とB列を足してC列に入れるだけの処理を書いています ************************************/ var ss_url = "URL"; function get_step_by_step(){ var ss = SpreadsheetApp.openByUrl(SS_URL); var sh = ss.getSheets()[0]; var last_row = get_last_row(sh) + 1; var step = 4; var valueA = sh.getRange("A" + last_row + ":A" + (last_row + step)).getValues(); var valueB = sh.getRange("B" + last_row + ":B" + (last_row + step)).getValues(); Logger.log([last_row, valueA.length, valueA, valueB]) for(var i = 0; i < valueA.length; i++){ var valueC = valueA[i] + valueB[i]; sh.getRange("C" + (last_row + i)).setValue(valueC); } } function get_last_row(sh) { var values = sh.getRange("C:C").getValues(); for (var i = values.length - 1; i >= 0; i--) { if (values[i] != "") { break; } } var last_row = i + 1; return last_row; } |
A, B列に1~9まで入力しておいて
get_step_by_step() を実行すると
C列には結合した値が入力される
参考
JIRA APIでステータスをtransitionで更新する
JIRAのstatusをAPIで更新するにはtransitionでやるらしい
https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-issue-issueIdOrKey-transitions-post
- transitoin idを確認する
https://SITENAME.atlassian.net/rest/api/2/issue/ISSUE_KEY/?expand=transitions.fields - transition idをPOSTで更新する
コード.gs
function get_jira_token() { var id = "LOGIN_EMAIL"; var pw = "LOGIN_PASSWORD"; var jira_token = Utilities.base64Encode(id + ":" + pw); return jira_token; } function get_base_url() { var base_url = "https://SITENAME.atlassian.net/rest/api/2/issue/"; return base_url; } /************************************ まずはtransitionsを取得してログに出して変更したいステータスのidを見つける ...{"id":"31","name":"完了"... などと取得できる ************************************/ function get_issue() { var token = get_jira_token(); var key = "KEY-1"; var options = { contentType: "application/json", headers: {"Authorization": " Basic " + token} }; var url = get_base_url() + key + "?expand=transitions.fields"; var response = UrlFetchApp.fetch(url, options); Logger.log(response); } /************************************ transitionを変更する var transitions = {"transition": {"id": "31"}} などと書いて変更する ************************************/ function change_transition() { var token = get_jira_token(); var payload = get_payload(); var options = get_options(token, payload); var url = get_url(); UrlFetchApp.fetch(url, options); } function get_url(){ var key = "KEY-1"; var url = get_base_url() + key + "/transitions"; return url; } function get_payload(values) { var transitions = {"transition": {"id": "31"}} var payload = JSON.stringify(transitions); return payload; } function get_options(token, payload) { var options = { method: "post", payload: payload, contentType: "application/json", headers: {"Authorization": " Basic " + token} } return options; } |
参考
Do transition
https://developer.atlassian.com/cloud/jira/platform/rest/#api-api-2-issue-issueIdOrKey-transitions-post
JIRA APIでカスタムフィールドの値を更新する
JIRAのAPIで特定のカスタムフィールドの値を変更したくて書いたコードです。
コード.gsfunction get_jira_token() { var id = "LOGIN_EMAIL"; var pw = "LOGIN_PASSWORD"; var token = Utilities.base64Encode(id + ":" + pw); return token; } function get_base_url() { var base_url = "https://SITENAME.atlassian.net/rest/api/2/issue/"; return base_url; } function update() { var token = get_jira_token(); var payload = get_payload(); var options = get_options(token, payload); var url = get_url(); UrlFetchApp.fetch(url, options); } function get_url(){ var key = "KEY-1"; var url = get_base_url() + key; return url; } function get_payload(values) { var email = Session.getActiveUser().getEmail(); var data = { customfield_10025: "対象のカスタムフィールドに入れる値" }; var fields = {fields: data}; var payload = JSON.stringify(fields); return payload; } function get_options(token, payload) { var options = { method: "PUT", payload: payload, contentType: "application/json", headers: {"Authorization": " Basic " + token} } return options; } |
上記コード内の以下の値を設定してから
- LOGIN_EMAIL
- LOGIN_PASSWORD
- SITENAME
update() を実行すると以下のようにカスタムフィールドの値が更新できる
参考
JIRA REST API examples
https://developer.atlassian.com/server/jira/platform/jira-rest-api-examples/
2018年5月17日木曜日
画面遷移前にアラートを出す
今いるページで何か操作をしてから画面遷移する前に以下のようなダイアログを出したい
デモ
上のテキストエリアに何か文字を入力してから
このページを閉じたり更新したり別のページへ移動したり
しようとすると確認ダイアログが表示されます
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <body> <textarea></textarea> <script> window.onbeforeunload = function(e) { return e.returnValue; } </script> </body> </html> |
意訳テキストエリア 画面遷移前に 確認ダイアログを返す |
補足
参考にしたサイトではダイアログにメッセージを表示できそうにかかれていましたが
手元で試したところメッセージは渡せずに
行った変更が保存されない可能性があります。
という固定の文字列しか表示できなかった。
こういうhtmlを試してみた
index.html<!DOCTYPE html> <html> <body> <textarea></textarea> <script> window.onbeforeunload = function(e) { var dialogText = '本当にこのページを離れていいですか?'; e.returnValue = dialogText; return dialogText; }; </script> </body> </html> |
本当にこのページを離れていいですか?
はダイアログに表示されず
行った変更が保存されない可能性があります。
が表示された。
参考
window.onbeforeunload
https://developer.mozilla.org/ja/docs/Web/API/WindowEventHandlers/onbeforeunload
window.onbeforeunload
https://developer.mozilla.org/ja/docs/Web/API/WindowEventHandlers/onbeforeunload
2018年5月13日日曜日
claspで.clasp.jsonが作成されずScript IDが紐付かない時にやったこと
やったこと
- なぜか一つ上の階層に.clasp.jsonが存在していたのでそれを消した
- macOSの隠しファイルは「コマンド」+「シフト」+「ピリオド」で表示
- .clasp.jsonが作成されていなかったディレクトリの中身を空にしてcloneし直す
- すると.clasp.jsonが作成されてscript IDも保存された
2018年5月12日土曜日
macOS High Sierraで隠しファイルを表示する
キーボードショートカット
commad + shift + .(コマンド+シフト+ピリオド)
コマンドライン
フォルダに移動して$ ls -a
参考
「macOS High Sierraで隠しファイルを表示する」
でググるとたくさんヒットしましたが
Mac のキーボードショートカットには載っていませんでした
情報源はどこなんだろう。。
Communitiesで質問と回答は見つかった↓
https://discussions.apple.com/thread/7581737
claspを使ってみる
claspをMacにインストールして使ったときの手順
公式の手順に沿ってやってみる
https://codelabs.developers.google.com/codelabs/clasp/#0
$ sudo npm install n -g $ sudo n latest $ npm i @google/clasp -g →npm update check failed │ │ Try running with sudo or get access │ │ to the local update config store via │ │ sudo chown -R $USER:$(id -gn $USER) /Users/NAME/.config
と言われたので
$ sudo npm i @google/clasp -g $ clasp $ clasp login
→ブラウザが起動してログインすると
Logged in! You may close this page.と出る
フォルダを作ってそこに新規スクリプトファイルを作成する
$ mkdir clasp_codelab && cd clasp_codelab $ clasp create "clasp Codelab" →Error: Permission denied. Enable the Apps Script API:
と言われるので
https://script.google.com/home/usersettings
でAPIをオンにしてリトライ
$ clasp create "clasp Codelab"
これで新規スクリプトファイルは作成できた
ドライブ内のファイルを開くには
$ clasp open
オンラインのプロジェクトをローカルに持ってくるときは
$ clasp clone SCRIPT ID
オンラインのプロジェクトを編集してからローカルに反映するときは
$ clasp pull
ローカルのプロジェクトを編集してオンラインに反映するときは
$ clasp push
このあとオンラインのプロジェクトを再読込すると反映を確認できる
バージョンを保存するときは
$ clasp version "説明"
Webアプリをデプロイする場合
$ clasp deploy 2 "Second deployment"
一度もデプロイされていないとこのコマンドは使えないらしい
(スクリプトエディタ上で事前に一度アプリをデプロイしておく必要がある)
参考
Command Line Interface using clasp
https://developers.google.com/apps-script/guides/clasp
clasp - The Apps Script CLI
https://codelabs.developers.google.com/codelabs/clasp/#0
GitHub google/clasp
https://github.com/google/clasp
G Suite Developers Blog
https://gsuite-developers.googleblog.com/2018/01/three-new-tools-to-help-improve-your.html?m=1
2018年5月7日月曜日
改行で区切った文字列からJSON形式の文字列を作成する
テキストを入力して
JSON作成ボタンをクリックしたら
JSON文字列が作成される
というアプリケーション
コード.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="input_text" class="ta"></textarea><br> <button id="create_json_bt">JSON作成</button><br> <textarea id="json_text" class="ta"></textarea><br> <script> var input_text = document.getElementById("input_text"); var json_text = document.getElementById("json_text"); var create_json_bt = document.getElementById("create_json_bt"); create_json_bt.onclick = create_json_bt_clicked; function create_json_bt_clicked() { var text = input_text.value; var text_split = text.split("\n"); var array = []; for (var i = 0; i < text_split.length; i++) { var obj = {} obj["text"] = text_split[i]; array.push(obj); } var json = JSON.stringify(array); json_text.value = json; } </script> </body> </html> |
意訳taのスタイル 幅 高さ 入力エリア JSON作成ボタン JSON出力エリア idがinput_textの要素を取得する idがjson_textの要素を取得する idがcreate_json_btの要素を取得する create_json_btがクリックされたらcreate_json_bt_clickedを実行する この機能がやること input_textの値を取得して 改行で区切って 結果を入れる配列を用意して 区切った値の数だけ以下を繰り返す オブジェクトの入れ物を用意して {"text": text_split[i]の値}を作って arrayに追加する arrayをJSONに変換して JSONの出力エリアに入れる |
2018年5月6日日曜日
オブジェクトを二次元配列にして返す
このようなオブジェクトを
var obj = [ {"en": "Aries", "ja": "おひつじ座"}, {"en": "Taurus", "ja": "おうし座"}, {"en": "Gemini", "ja": "ふたご座"}, {"en": "Cancer", "ja": "かに座"}, {"en": "Leo", "ja": "しし座"}, {"en": "Virgo", "ja": "おとめ座"}, {"en": "Libra", "ja": "てんびん座"}, {"en": "Scorpius", "ja": "さそり座"}, {"en": "Sagittarius", "ja": "いて座"}, {"en": "Capriconus", "ja": "やぎ座"}, {"en": "Aquarius", "ja": "みずがめ座"}, {"en": "Pisces", "ja": "うお座"} ]
このような配列にして返したり
[[Aries, おひつじ座], [Taurus, おうし座], [Gemini, ふたご座], [Cancer, かに座], [Leo, しし座], [Virgo, おとめ座], [Libra, てんびん座], [Scorpius, さそり座], [Sagittarius, いて座], [Capriconus, やぎ座], [Aquarius, みずがめ座], [Pisces, うお座]]
このように改行を入れて返したり
Aries,おひつじ座
Taurus,おうし座
Gemini,ふたご座
Cancer,かに座
Leo,しし座
Virgo,おとめ座
Libra,てんびん座
Scorpius,さそり座
Sagittarius,いて座
Capriconus,やぎ座
Aquarius,みずがめ座
Pisces,うお座
したくて書いたコードです
コード.gs
var obj = [ {"en": "Aries", "ja": "おひつじ座"}, {"en": "Taurus", "ja": "おうし座"}, {"en": "Gemini", "ja": "ふたご座"}, {"en": "Cancer", "ja": "かに座"}, {"en": "Leo", "ja": "しし座"}, {"en": "Virgo", "ja": "おとめ座"}, {"en": "Libra", "ja": "てんびん座"}, {"en": "Scorpius", "ja": "さそり座"}, {"en": "Sagittarius", "ja": "いて座"}, {"en": "Capriconus", "ja": "やぎ座"}, {"en": "Aquarius", "ja": "みずがめ座"}, {"en": "Pisces", "ja": "うお座"} ] function make_arrays(){ var keys = Object.keys(obj[0]); var arrays = []; for(var i = 0; i < obj.length; i++){ var array = []; for(var j = 0; j < keys.length; j++){ var key = keys[j]; array.push(obj[i][key]); } arrays.push(array); } Logger.log(arrays); var rows = make_rows(arrays); Logger.log(rows); } function make_rows(arrays){ var rows = ""; for(var i = 0; i < arrays.length; i++){ rows += arrays[i] + "\n"; } return rows; } |
意訳JSONを用意する この機能がやること objのkeysを取得して(例の場合はenとjaがkey) 結果を入れる配列を用意して objの数だけ以下を繰り返す array配列を用意して keysの数だけ以下を繰り返す(例の場合はenとjaなのでkeysの数は2) keyにkeysの値を1つずつ入れて array配列に追加する arrays配列にarrayを追加する arraysをログに出す arraysをmake_rowsに渡して 結果をログに出す この機能がやること rowsという入れ物を用意して arraysの数だけ繰り返す rowsにarraysの値をひとつずつ改行を付けて足して rowsを返す |
実行結果
テキストエリアの値をローカルにダウンロードする
テキストエリアに入力したテキストをローカルにダウンロードしたい
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <body> <textarea id="ta"></textarea><br> <input type="text" id="file_name" value="ファイル名"> <input type="text" id="content_type" value="text/plain"><br> <button id="button">Download</button> <script> var download_button = document.getElementById("button"); download_button.onclick = download; function download() { var data = document.getElementById("ta").value; var file_name = document.getElementById("file_name").value; var content_type = document.getElementById("content_type").value; var blob = new Blob([data], {"type":content_type}); var link = document.createElement("a"); link.download = file_name; link.href = window.URL.createObjectURL(blob); link.click(); } </script> </body> </html> |
意訳テキスト入力エリア ファイル名を入れるテキストボックス ContentTypeを指定するテキストボックス ダウンロードボタン idがbuttonの要素を取得して クリックされたらdownloadを実行する この機能がやること テキストエリアの値を取得して ファイル名を取得して content_typeを取得して Blobに入れて a要素を作成して ダウンロードするファイル名に指定して URLを作成して クリックしてダウンロードする |
参考
window.URL.createObjectURL
https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL
<a>
https://developer.mozilla.org/ja/docs/Web/HTML/Element/a
window.URL.createObjectURL
https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL
<a>
https://developer.mozilla.org/ja/docs/Web/HTML/Element/a
2018年5月5日土曜日
RawGitでgithubに置いた.jsを読み込む
RawGitでgithubに置いた.jsを読み込んでみたときの備忘録
https://rawgit.com/
で対象のファイルのURLを貼り付けると
production と developmentの欄にURLが表示される
試してみたこと
テストで何度もコードを更新する場合はdevelopmentのURLを使うと更新されたコードが読み込まれる
→トラフィックが多すぎると制限される
productionはトラフィックの制限はないが、コードを更新しても更新されたコードは読み込まれない
→更新されたコードを読み込む場合は更新後に再度対象のgithubのURLを貼り付けると新しいURLが表示される(URL内にあるcommit hashが更新される)
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="https://cdn.rawgit.com/prepractice/javascript/a2763ed6/library/array_unique_count.js"></script> </head> <body> <script> unique_count(); function unique_count() { var values = ["hello", "hi", "hey", "hey", "hey", "hello"]; var obj = arrayUniqueCount(values); alert(JSON.stringify(obj)); } </script> </body> </html> |
意訳RawGitサイトで作られたproductionURLをスクリプトで読み込む unique_count()を実行する この機能がやること 配列を用意する arrayUniqueCountに渡して結果を取得して アラートに出す |
実行結果
https://rawgit.com/
今回試した自作のコード
配列を渡すと要素の値をユニークにしてその数をカウントしてオブジェクトで返す
https://github.com/prepractice/javascript/blob/master/library/array_unique_count.js
配列を渡すと要素の値をユニークにしてその数をカウントしてオブジェクトで返す
https://github.com/prepractice/javascript/blob/master/library/array_unique_count.js
参考
RawGithttps://rawgit.com/
2018年5月4日金曜日
Custom Search APIで画像の検索結果を取得する
Custom Search APIの設定をしてから
以下の検索URLの「取得したAPIKEY」「取得したCSE_ID」「検索したいテキスト」を置き換えてブラウザで開くと検索結果を得られる
検索URL:
https://www.googleapis.com/customsearch/v1?key=取得したAPIKEY&cx=取得したCSE_ID&searchType=image&q=検索したいテキスト
Google Custom Search APIの設定
1日あたり100件の検索クエリまでは無料など、利用上の制限もあるようです
http://www.pre-practice.net/2017/12/google-custom-search-api.html#limit
HTML Serviceで試したときの検索例を書き残しておきます
このアプリケーションでできること
- テキストボックスに検索テキストを入力して
- 検索ボタンを押すと
- 検索URLをUrlFetchして内容を取得して
- title, link, snippet, contextLinkなどを取得して
- HTML要素を作って結果を表示する
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('index'); } var API_KEY = "取得したAPI_KEY"; var CSE_ID = "取得したCSE_ID"; var BASE_URL = "https://www.googleapis.com/customsearch/v1?key="; var CX = "&cx="; var IMAGE = "&searchType=image"; var Q = "&q="; function get_value_gs(query) { var url = BASE_URL + API_KEY + CX + CSE_ID + IMAGE + Q + encodeURIComponent(query); var fetch = UrlFetchApp.fetch(url).getContentText(); var obj = JSON.parse(fetch); var items = obj["items"]; var array = []; for (var i = 0; i < items.length; i++) { var obj_items = {}; var item = items[i]; var title = item["title"]; var link = item["link"]; var snippet = item["snippet"]; var context_link = item["image"]["contextLink"]; obj_items["title"] = title; obj_items["link"] = link; obj_items["snippet"] = snippet; obj_items["contextLink"] = context_link; array.push(obj_items); } return array; } |
意訳この機能がやること 指定したHTMLファイルを表示する 取得したAPI_KEY 取得したCSE_ID BASE_URL CX IMAGE Q この機能がやること 受け取ったqueryでurlを作ってエンコードして customsearchAPIから返ってきた内容を取得して JSONを解析してオブジェクトに変換して itemsを取得して 結果の入れ物を配列で用意して itemsの数だけ以下を繰り返す obj_itemsという名で新規オブジェクトを作る itemsを一つずつ取得して titleを取得して linkを取得して smippetを取得して imageのcontextLinkを取得して obj_items { "title": title, "link": link, "snippet": snippet, "contextLink": contextLink} を作る array配列にobj_itemsを追加する 出来上がったarrayを返す |
上のコード.gsはHTML Serviceで使うためにqueryを受け取ってarrayを返してしています
HTML ServiceでUIを作る
index.html<!DOCTYPE html> <html> <head> <style> .card { width: 25%; height: auto; padding: 15px; border-radius: 2px; border: solid 1px lightgray; box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); overflow-wrap: break-word; } .break_word { overflow-wrap: break-word; } .flex_div { display: flex; flex-direction: row; } .img_size { width: 60%; height: auto; } .underline_none { text-decoration: none; } </style> </head> <body> <input type="text" id="tb"> <button id="bt">画像検索</button> <div id="main_div"></div> <script> var bt = document.getElementById("bt"); var tb = document.getElementById("tb"); bt.onclick = bt_clicked; function bt_clicked() { var value = tb.value; google.script.run .withFailureHandler(onFailure) .withSuccessHandler(onSuccess) .get_value_gs(value); } function onSuccess(array) { create_elements(array); } function onFailure(e) { alert(["error" + e.message, e.stack]); } function create_elements(array) { for(var i = 0; i < array.length; i++){ var div_h = create_div_horizontal(); var div_img_card = create_card(div_h); create_image(div_img_card, array[i]["link"]); var div_link_card = create_card(div_h); create_link(div_link_card, array[i]["title"], array[i]["contextLink"]); var div_text_card = create_card(div_h); create_text_div(div_text_card, tb.value); } } function create_div_horizontal() { var main_div = document.getElementById('main_div'); var div_h = document.createElement("div"); div_h.setAttribute("class", "flex_div"); main_div.appendChild(div_h); return div_h; } function create_card(div_h) { var div_link_card = document.createElement("div"); div_link_card.setAttribute("class", "card"); div_h.appendChild(div_link_card); return div_link_card } function create_link(div_h, title, item) { var link = document.createElement("a"); link.setAttribute("class", "underline_none"); link.setAttribute("href", item); link.setAttribute("target", "_blank"); link.textContent = title; div_h.appendChild(link); } function create_image(div_img_card, item) { var link = document.createElement("a"); var img = document.createElement("img"); link.setAttribute("href", item); link.setAttribute("target", "_blank"); img.setAttribute("class", "img_size"); img.setAttribute("src", item); img.textContent = item; link.appendChild(img); div_img_card.appendChild(link); } function create_text_div(div_h, text) { var div = document.createElement("div"); div.textContent = text; div_h.appendChild(div); } </script> </body> </html> |
2018年5月2日水曜日
文字列の中から漢字を抽出する正規表現を考えてみる /[々〆〇〻㐂-頻]+/g
本文がちょっと込み入っているので、まずは結果から書きます
今回書いた漢字を抽出する正規表現はこれ
/[々〆〇〻㐂-頻]+/g
調べてみると漢字の範囲は奥が深い
ひらがなやカタカナのように「ここからここまで」という始まりと終わりの文字がよくわからない
ひらがな:「あ」〜「ん」
カタカナ:「ア」〜「ン」
漢字:「?」〜「?」
今回調べて知ったこと・わかったこと等
- 常用漢字やJIS第1水準〜第4水準の漢字を文化庁のホームページやwikipediaで知った
(なんとなく知ってはいたが改めて調べて知った) - Unicodeは世界中の文字を1文字2バイトで65536字で表そうとしていた
- でも65536字では足りないことに気づいた
- 65536字では足りないので4バイトで1文字を表すサロゲートペアが作られた
- 常用漢字の中で唯一のサロゲートペアは「𠮟」
- ちなみに別の文字の「叱」は常用漢字ではないがJIS第1水準漢字
- 今回書いた [㐂-頻] はJIS第1水準〜第4水準の漢字だけを絞っているわけではない
- それ以外の漢字も範囲に含まれる
- この範囲は個人的に絞ったものなので一般的ではない
今回書いた正規表現で一致させたい漢字
- 㐂-頻の範囲に含まれるすべての漢字
- 注意点としてはJIS第1水準〜第4水準の漢字だけではないということ
- JIS第1水準〜第4水準の漢字を数値に置き換えて昇順に並び替えると先頭が 㐂 で末尾が 頻 ですが、その範囲内には第1〜第4に含まれない漢字も含まれる
- サロゲートペアも含まれる
- 々:上記の範囲に含まれないため直接追加
- 〆:「しめ」「閉め」「締め」「絞め」「占め」などを表す
- 〇:漢字のゼロ
- 〻:現在は「々」で代用されることもある(上字の訓を繰り返す)
※JIS第1水準〜第4水準の漢字だけを抽出するにはこの正規表現では不十分です
Unicode 10.0 Character Code Charts
http://www.unicode.org/charts/ を見ると
2018/01/29現在以下のような種類があり今後ExtensionG以降も増えそう
- CJK Unified Ideographs (Han) Range: 4E00–9FEA 統一漢字
- CJK Extension-A Range: 3400–4DB5 拡張A
- CJK Extension B Range: 20000–2A6D6 拡張B
- CJK Extension C Range: 2A700–2B734 拡張C
- CJK Extension D Range: 2B740–2B81D 拡張D
- CJK Extension E Range: 2B820–2CEA1 拡張E
- CJK Extension F Range: 2CEB0–2EBE0 拡張F
- CJK Compatibility Ideographs Range: F900–FAFF 互換漢字
- CJK Compatibility Ideographs Supplement Range: 2F800–2FA1F 互換漢字補足
- CJK Radicals / KangXi Radicals Range: 2F00–2FDF 部首
- CJK Radicals Supplement Range: 2E80–2EFF 部首補足
- CJK Strokes Range: 31C0–31EF おそらく一画ごとの表
- Ideographic Description Characters Range: 2FF0–2FFF おそらく配置
wikipediaでCJK統合漢字を見てみるとだいぶ複雑な歴史を経ている
16進数で表してみる
/[々〆〇〻㐂-頻]+/g
を
16進数で表す場合は、おそらくこのようになる
/[\u3005\u3006\u3007\u303b\u3402-\uFA6A\uD840-\uD869\uDC02-\uDFFF]+/g
それぞれの16進数が意味している文字は
3005:々
3006:〆
3007:〇
303B:〻
3402:㐂
FA6A:頻
D840:𠀋の上位サロゲート(範囲内のサロゲートペアの上位サロゲートで一番小さい)
D869:𪚲の上位サロゲート(範囲内のサロゲートペアの上位サロゲートで一番大きい)
DC02:𦐂の下位サロゲート(範囲内のサロゲートペアの下位サロゲートで一番小さい)
DFFF:𣟿の下位サロゲート(範囲内のサロゲートペアの下位サロゲートで一番大きい)
今回書いた正規表現を使って漢字を抽出してみる
コード.gsfunction get_kanji(){ var str = "abcABC123abcABC123かなカナカナ仮名ひらがなカタカナカタカナ漢字"; var pattern = /[々〆〇〻㐂-頻]+/g; var result = str.match(pattern); Logger.log(result); } | 意訳この機能がやること 探索対象の文字列を用意しておく 今回書いた漢字のパターン 一致するものを探して ログに出す |
実行結果
参考
Unicode 10.0 Character Code Charts
http://www.unicode.org/charts/
wikipedia
CJK統合漢字
https://ja.wikipedia.org/wiki/CJK%E7%B5%B1%E5%90%88%E6%BC%A2%E5%AD%97
常用漢字一覧
https://ja.wikipedia.org/wiki/%E5%B8%B8%E7%94%A8%E6%BC%A2%E5%AD%97%E4%B8%80%E8%A6%A7
漢字
https://ja.wikipedia.org/wiki/%E6%BC%A2%E5%AD%97
常用漢字表(平成22年内閣告示第2号)
http://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
日本漢字能力検定
級別漢字表
http://www.kanken.or.jp/kanken/outline/data/outline_degree_national_list.pdf
正規表現を書いてmatchで抽出する
正規表現を変数にして一致する文字を出力するUIを作ってみる
デモ
.match(
)
コード.gs
function doGet() { return HtmlService.createHtmlOutputFromFile("index"); } |
意訳この機能がやること 指定したHTMLファイルを表示する |
index.html
<!DOCTYPE html> <html> <head> <style> .ta { width: 360px; height: 120px; } .flag { width: 60px; } .text_dimgray { color: dimgray; } .text_orange { color: darkorange; font-weight: bold; font-size: 16px; } .regexp { font-size: 16px; } </style> </head> <body> <label class="text_dimgray">この文字列の中から一致する文字列を探したい</label> <br> <textarea id="input" class="ta"></textarea> <br> <div class="regexp">.match( <label class="text_orange">/ <input type="text" id="tb" class="text_orange" placeholder="一致させたい文字列">/ <input type="text" id="tb_flag" class="flag text_orange" placeholder="g,i,m等"> </label>) </div> <br> <label class="text_dimgray">一致する文字列</label> <br> <textarea id="output" class="ta"></textarea> <script> var tb = document.getElementById("tb"); var tb_flag = document.getElementById("tb_flag"); var input = document.getElementById("input"); var output = document.getElementById("output"); tb.onkeyup = get_result; tb_flag.onkeyup = get_result; function get_result() { var target = tb.value; var flag = tb_flag.value; var pattern = new RegExp(target, flag); output.value = input.value.match(pattern); } </script> </body> </html> |
意訳taのスタイル 幅 高さ flagのスタイル 幅 text_dimgrayのスタイル 文字色 text_orangeのスタイル 文字色 文字の太さ 文字サイズ regexpのスタイル 文字サイズ ラベル インプットエリア 正規表現を入力するエリア ラベル 出力エリア idがtbの要素を取得 idがtb_flagの要素を取得 idがinputの要素を取得 idがoutputの要素を取得 tbでキーが上がったらget_resultを実行する tb_flagでキーが上がったらget_resultを実行する この機能がやること tbのvalue(正規表現)を取得して tb_flagのvalue(フラグ)を取得して 正規表現のオブジェクトを作成して output(出力エリア)に一致する文字列を出力する |
2018年5月1日火曜日
配列内の要素の組み合わせを列挙する(ペアのパターン)
["いちご", "めろん", "もも", "ぶどう"]
という配列の要素から2つ取り出した時の組み合わせ(nCr)のパターンを列挙してみる
このような感じで
[
[いちご めろん, いちご もも, いちご ぶどう],
[めろん もも, めろん ぶどう],
[もも ぶどう]
]
簡単に書けそうな気がして書いてみたら意外と考えさせられました
その1とその2の実行結果は同じです
組み合わせのパターンの数だけを出す場合
コードを書かずにすぐに使えるデモもほしくて作りました
(このデモはブログに直接HTML/CSS/JSを書いたもの)
上の入力エリアに
いちご
めろん
もも
ぶどう
と入れてget pairsボタンをクリックすると
下の出力エリアに半角スペースでつながった2つのワードのパターンが出力される
いちご めろん,いちご もも,いちご ぶどう,めろん もも,めろん ぶどう,もも ぶどう
デモの入力例
.gs内でパターンのログを出してみる
コードの例 その2
下にあるその1よりも短く書いたコード
コード2.gsfunction get2word_patterns() { var array = ["いちご", "めろん", "もも", "ぶどう"]; var patterns = []; for (var a = 0; a < array.length - 1; a++) { var pattern = []; for (var i = a; i < array.length - 1; i++) { var head = array[a]; var add = array[i + 1]; pattern.push(head + " " + add); } patterns.push(pattern); pattern = []; } Logger.log(patterns); } | 意訳この機能がやること 配列を用意する 結果を入れるpatterns配列を用意する array配列-1だけ繰り返す 途中結果を入れるpattern配列を用意する iにaを入れてarray配列-1より小さければiを足して以下を繰り返す array配列のa番目と array配列のi+1番目を 半角スペースでつないでpatternに追加する patterns配列にpatternを追加して pattern配列を空に戻して 出来上がったpatternsをログに出す |
コードの例 その1
コード1.gsfunction get2word_patterns() { var original = ["いちご", "めろん", "もも", "ぶどう"] var array = original.slice(); var patterns = []; var pattern = []; var parent = array.shift(); var childs = array.slice(); var i = 0; while(i < original.length-1){ if(childs != ""){ var child = childs.shift(); pattern.push([parent + " " + child]); }else{ patterns.push(pattern); pattern = []; parent = array.shift(); childs = array.slice(); i++; } } Logger.log(patterns); } | 意訳この機能がやること originalという名で配列を用意して その配列をsliceでコピーする patternsの入れ物 patternの入れ物 array配列の先頭を抜き出してparentに入れて 先頭を抜き出したarray配列の残りをchildsに入れて iの初期値は0 iがoriginalの長さ-1より小さい限り以下を繰り返す もしchilds配列が空じゃなければ childs配列の先頭を抜き出して patternにparent childを半角スペースでつなげて追加する childs配列が空になったら patternsにpatternを追加して patternを空に戻して array配列の先頭を抜き出してparentに入れて 先頭を抜き出したarray配列の残りをchildsに入れて iをカウントアップしていく 出来上がったpatternsをログに出す |
実行結果
HTML ServiceでUIを作ってみる
コード.gsfunction doGet() { return HtmlService.createHtmlOutputFromFile('index'); } | 意訳この機能がやること 指定したHTMLファイルを表示する |
index.html<!DOCTYPE html> <html> <head> <style> .ta { width: 360px; height: 240px; } </style> </head> <body> <textarea id="INPUT_VALUE" class="ta"></textarea> <br> <button id="BT">get pairs</button> <br> <textarea id="OUTPUT_VALUE" class="ta"></textarea> <script> var INPUT_VALUE = document.getElementById("INPUT_VALUE"); var OUTPUT_VALUE = document.getElementById("OUTPUT_VALUE"); var BT = document.getElementById("BT"); BT.onclick = get2word_patterns; function get2word_patterns() { var array = INPUT_VALUE.value.split("\n"); var patterns = []; for (var a = 0; a < array.length - 1; a++) { var pattern = []; for (var i = a; i < array.length - 1; i++) { var head = array[a]; var add = array[i + 1]; pattern.push(head + " " + add); } patterns.push(pattern); pattern = []; } OUTPUT_VALUE.value = patterns.toString() } </script> </body> </html> | 意訳taのスタイル 幅 高さ 入力エリア 実行ボタン 出力エリア INPUT_VALUEの要素を取得 OUTPUT_VALUEの要素を取得 BTの要素を取得 BTをクリックしたらget2word_patternsを実行する この機能がやること 配列を用意する 結果を入れるpatterns配列を用意する array配列-1だけ繰り返す 途中結果を入れるpattern配列を用意する iにaを入れてarray配列-1より小さければiを足して以下を繰り返す array配列のa番目と array配列のi+1番目を 半角スペースでつないでpatternに追加する patterns配列にpatternを追加して pattern配列を空に戻して 出来上がったpatternsをログに出す |
補足
コードだけ見てるとよくわからなくなってきたので
コード1.gsの方を例に何をやっているのか書き出してみる
どっちが前でどっちが後ろかの順番は関係なくペアのパターンを作りたい
用意する配列の例
original
["いちご", "めろん", "もも", "ぶどう"]
その配列をshiftして行くので、その前にオリジナルを残しておく→.slice()でコピーを作れる(シャローコピー)
array = original.slice()
["いちご", "めろん", "もも", "ぶどう"]
要素のペアを作りたいので、順番に要素を抜き出してペアを作っていく
そのためにarrayをshiftしてまずは0番目を抜き出し、そこに残りの要素をくっつけていく
parent = array.shift()
"いちご"
残りのarrayは["めろん", "もも", "ぶどう"]
childs = array.slice()
["めろん", "もも", "ぶどう"]
originalの要素数は4つだけど最後の"ぶどう"は後ろにくっつける要素がないので-1
for(var i = 0; i < original.length-1;){
後ろにくっつける要素がある限り
if(childs != "")
childsの中からひとつずつ要素を抜き出して
child = childs.shift()
→"めろん"
→残りのarrayは["もも", "ぶどう"]
parentとchildをセットにしてpatternに追加していく
pattern.push([parent, child]);
→"いちご", "めろん"
後ろにくっつける要素がなくなったら
}else{
ここまでに作ったpattern配列をpatterns配列に追加する
patterns.push(pattern)
→[["いちご", "めろん"], ["いちご", "もも"], ["いちご", "ぶどう"]]
次のpatternを作るためにpattern配列を空に戻して
pattern = []
次のparentをarray["めろん", "もも", "ぶどう"]から抜き出して
parent = array.shift()
→"めろん"
残りのarrayは["もも", "ぶどう"]なので
childs = array.slice()
でコピー
→["もも", "ぶどう"]
これを繰り返してすべてのペアを作って
出来上がったパターンをログに出す
Latest post
Googleドキュメントに見出しを追加したい
今回の例では、ドキュメントの末尾に「見出しD」 を追加します。 見出しA, B, C, Dのスタイルは、見出し3 ( HEADING3 ) に設定しています。 下記Code.gsの GOOGLE_DOCUMENT_URL を設定して addHeadingToEnd() を...