Last active
February 1, 2023 13:54
-
-
Save Tomokatsu-Sakamoto/b627294f7fbe9b97f5a075609b8930b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; // 変数の宣言を強要する | |
const OUTPUT_VALUE = 0; // 書き出す内容に単位を付けるか?(0:付ける、2:付けない) | |
// 関数 currentRowProc で使用する定数(あとで解析する) | |
const READ_COLUMNS = 10; // 読み込むセル数 | |
const WRITE_COLUMN1 = 5; // 書き込むセル位置(平均キータイプ数) | |
const WRITE_COLUMN2 = 6; // 書き込むセル位置(ミスタイプ数) | |
// 関数 onFormSubmit で使用する定数(トリガー関数で解析する) | |
const SHEET_NAME = '解析結果'; // 解析結果を保存するシート名 | |
/** | |
* トリガー関数として、フォームからの回答を解析して、別シートに解析結果とあわせて出力する | |
* | |
* ※この関数を実行するときには、SHEET_NAME の設定が必要で、当該シートが存在していなければならない | |
*/ | |
function onFormSubmit(e) { | |
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); | |
let outData = e.values; // フォームからの回答結果 | |
let res = procRowData(outData); // 回答結果を解析する | |
outData.push(res[OUTPUT_VALUE + 1]); | |
outData.push(res[OUTPUT_VALUE + 2]); | |
sheet.appendRow(outData); // 出力用のシートに解析結果とともに書き出す | |
} | |
/** | |
* 現在のカーソル行を処理して、既定の列に解析結果を書き込む | |
* | |
* ※この関数を実行するときには、READ_COLUMNS、WRITE_COLUMN1、WRITE_COLUMN2 の設定が必要 | |
*/ | |
function currentRowProc() { | |
let sheet = SpreadsheetApp.getActiveSheet(); // 現在開いているスプレッドシート | |
let row = sheet.getActiveRange().getRow(); | |
let datas = sheet.getRange(row, 1, 1, READ_COLUMNS).getValues(); | |
let res = procRowData(datas[0]); // 現在のカーソル行を処理する | |
sheet.getRange(row, WRITE_COLUMN1).setValue(res[OUTPUT_VALUE + 1]); | |
sheet.getRange(row, WRITE_COLUMN2).setValue(res[OUTPUT_VALUE + 2]); | |
} | |
/** | |
* 与えられた行データをもとにして、 | |
* ① アップロードされた画像ファイルの抽出(どの列に URL が保存されているか?) | |
* ② 画像ファイルの解析(与えられた画像ファイルをテキスト化) | |
* ③ 解析結果から目的の値を抽出 | |
* ④ 処理結果を配列として戻す | |
*/ | |
function procRowData(rowData) { | |
let fileId = ''; // 画像ファイルのファイル ID | |
// ① アップロードされた画像ファイルの抽出(どの列に URL が保存されているか?) | |
for (let i = 0; i < rowData.length; i++) { | |
let url = String(rowData[i]); // 文字列として扱うために変換 | |
let idx = url.indexOf('https:'); // 'https:' が含まれていれば、アップロードされた画像ファイルと判断 | |
if (idx != -1) { | |
let urlSplit = url.split(/id=/); | |
fileId = urlSplit[1]; | |
break; | |
} | |
} | |
return imageReadOCR(fileId); // ②〜④ は別の関数で処理 | |
} | |
/** | |
* 指定されたファイル ID の画像ファイルを読み込んで、「平均キータイプ数」「ミスタイプ数」を配列として戻す | |
*/ | |
function imageReadOCR(id) { | |
/** | |
* 参考: | |
* GAS x OCRで画像から文字を簡単に抜き出す方法【Google Apps Scriptチュートリアル】 | ふくのブログ | |
* https://fuku-fk.com/gas-ocr-text/ | |
*/ | |
const image = Drive.Files.copy( // 画像ファイルを OCR 機能でテキスト化 | |
{ title: "tmp" }, | |
id, | |
{ "ocr": true, "ocrLanguage": "ja" } | |
); | |
const text = DocumentApp.openById(image.id).getBody().getText(); | |
let strSplit = text.split(/\n| /); // テキスト化した内容を分割して配列に格納 | |
console.log(strSplit, strSplit.length); | |
// 「平均キータイプ数」を探し出す | |
let val1, val2, val3, val4, idx; | |
for (let i = 0; i < strSplit.length; i++) { // 基準とする '回/秒' を探す | |
let base = String(strSplit[i]); // 文字列として扱うために変換 | |
if (base.indexOf('回/秒') != -1) { // '回/秒' が含まれている要素を探す | |
idx = i; | |
break; // 見つけた! | |
} | |
} | |
console.log(idx); | |
val1 = String(strSplit[idx]); | |
val3 = val1.replace('回/秒', ''); // 単位を取り除く | |
if (val3 == '') { // 数値と単位が分かれているケース | |
val1 = strSplit[idx - 1] + val1; | |
val3 = strSplit[idx - 1]; | |
} | |
// 「ミスタイプ数」を探し出す | |
do { | |
idx++; // 次の '回' を含む要素を探す | |
let base = String(strSplit[idx]); // 文字列として扱うために変換 | |
if (base.indexOf('回') != -1) { // '回/秒' が含まれている要素を探す | |
break; | |
} | |
} while (idx < strSplit.length); | |
val2 = String(strSplit[idx]); | |
val4 = val2.replace('回', ''); // 単位を取り除く | |
if (val4 == '') { // 数値と単位が分かれているケース | |
val2 = strSplit[idx - 1] + val2; | |
val4 = strSplit[idx - 1]; | |
} | |
let ret = [ // 処理結果を戻すための配列 | |
idx, // 0: 基準となるミスタイプの位置 | |
val1, // 1: [単位あり] 平均キータイプ数 | |
val2, // 2: [単位あり] ミスタイプ数 | |
val3, // 3: [単位なし] 平均キータイプ数 | |
val4, // 4: [単位なし] ミスタイプ数 | |
]; | |
Drive.Files.remove(image.id); // 作業ファイルを削除 | |
console.log(ret); | |
return ret; // 処理で得た値を戻す | |
} | |
/** | |
* 既存データをまとめて処理するための関数 | |
*/ | |
function sheetAllProc() { | |
let sheet = SpreadsheetApp.getActiveSheet(); // 現在開いているスプレッドシート | |
for (let i = 2; i < sheet.getMaxRows(); i++) { | |
sheet.setActiveSelection(sheet.getRange(i, 1)); | |
currentRowProc(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment