LoginSignup
3
3

More than 1 year has passed since last update.

【コピペ可】スプレッドシートからGoogleFormを自動生成

Posted at

image.png

こんにちは,だるだるし です
会社の代表してたり音声作品投稿してたりします
お金がありません,,,金か仕事をください,,,

はい,ていうのはおいておいて

Googleフォームの自動生成

目標

GoogleフォームをスプレッドシートとGASで自動生成する

前段

image.png

スタディステーション』という(うちの会社の)サービス(現在完全無料なので本当に”サービス”)がある.

各自がGoogleフォームで作成したテスト,問題を皆で共有,検索できるサービス.

ここに小学二年生用の九九のサンプルを投稿したかったが,ポチポチ作るのはめんどくさかったので自動化したい.

【GAS】スプレッドシートからテスト用のGoogleFormを自動生成する

上記の記事を参照した結果,以下気になったので一応プログラマとして改良する

  • 速度が遅い(多分毎回シートにアクセスしてるせい)
  • 自由記述の解答形式に対応
  • 汎用性を持たせる(選択肢や正答の数を無制限にする,セルを決め打ち指定するのを避ける)
  • 冗長で複雑な表現を修正(配列をオブジェクトにするなど)
  • その他軽微な機能追加

答え

さっくり答え
九九作った時の「スプレッドシート

で,Googleフォームを生成するGASのコード
正直変数名とかエラーハンドリングは適当にしてあるのでご了承

//データをオブジェクト形式に変換
function getDataObjects(keyRow, dataRow) {
  let dataObjects = [];
  let keys = [];
  for (let i in keyRow) {
    let key = keyRow[i];
    if (key) {
      keys[key] = {
        key: key,
        i: i,
      };
    }
  }
  for (let row of dataRow) {
    let obj = {};
    for (let k in keys) {
      let key = keys[k];
      obj[key.key] = row[key.i];
    }
    dataObjects.push(obj);
  }
  return dataObjects;
}

//メイン関数
function myFunction() {
  //シート名
  let sheet = SpreadsheetApp.getActive().getSheetByName('シート1');

  let lastRow = sheet.getLastRow();//行
  // let lastColumn = sheet.getLastColumn();//列
  let formData = {
    title: "Googleフォーム",
    description: "",
    order: false,
  };

  //全データ取得
  let _sheet = sheet.getDataRange().getValues();
  let _formData = getDataObjects(_sheet[0], [_sheet[1]])[0];

  //フォーム名と説明文を設定
  formData.title = _formData.title || formData.title;
  formData.description = _formData.description || formData.description;
  formData.order = (_formData.order == 1);
  Logger.log(formData);

  //フォームを作成
  let form = FormApp.create(formData.title);
  form.setDescription(formData.description);
  form.setShuffleQuestions(formData.order);

  //クイズモードに設定
  form.setIsQuiz(true);

  //問題データ
  let questions = getDataObjects(_sheet[3], _sheet.splice(5, lastRow - 1));

  //問題文・選択肢を作成
  for (let question of questions) {
    let choices;
    //正解の数によってラジオボタンまたは、チェックボックスに形式を変える
    let item;
    switch (question.format) {
      case 1: //数値解答
        item = form.addTextItem();
        let textValidation = FormApp.createTextValidation()
          .setHelpText('数値で入力してください')
          .requireNumber()
          .build();
        item.setValidation(textValidation);
        break;

      case 2: //記述
        item = form.addTextItem();
        break;

      default: //選択
        let n = 1;
        switch (question.multiple) {
          case 1: //複数解答 //チェックボックスの作成
            item = form.addCheckboxItem();
            choices = [];
            while (question["choices" + n] || question["choices" + n] === 0) {
              let correct = false;
              for (let i in question.numOfCorrect) {
                if (question["choices" + n] === question["answer" + i]);
                correct = true;
                break;
              }
              let choice = item.createChoice(question["choices" + n], correct);//text,isCorrect(booblean)
              choices.push(choice);
              n++;
            }
            break;

          default: //単一解答 //ラジオボタンの作成
            item = form.addMultipleChoiceItem();
            //選択肢と解答の番号を取得
            choices = [];
            while (question["choices" + n] || question["choices" + n] === 0) {
              let choice = item.createChoice(question["choices" + n], question["choices" + n] === question.answer1);
              choices.push(choice);
              n++;
            }
            break;
        }
        break;
    }

    //問題文・選択肢・配点・必須をセット
    item.setTitle(question.statement || "問題");
    if (choices) {
      item.setChoices(choices);
    }
    item.setPoints(question.points);
    // item.setRequired(true);

    //フィードバックをセット
    // Logger.log(question.feedback);
    // Logger.log(question.format);
    if (question.format != 2 && question.format != 1) {
      if (question.feedback) {
        item.setFeedbackForCorrect(FormApp.createFeedback().setText(question.feedback).build());
      }
      if (question.feedbackForI) {
        item.setFeedbackForIncorrect(FormApp.createFeedback().setText(question.feedbackForI).build());
      }
    }
  }
}

取り敢えず使い方

元となるスプレッドシートを作成

見にくくて申し訳ないですが,以下のようにスプレッドシートを作成.
スプレッドシートの作成方法は別の記事等を参照のこと
image.png

ざっくり解説

一行目は全体に共通する「キー」
二行目は全体に共通する「値」
三行目は空(無視される)
四行目は問題に関する「キー」
五行目はキーの説明(無視される)
六行目以降は問題の「値」(一行で一問)

一行目の「title」の直下の値がGoogleフォームの「タイトル」,
一行目の「description」の直下の値がGoogleフォームの「概要」
になる

同様に
四行目の「statement」の列が問題の「問題文」の列
四行目の「format」の列が問題の「解答形式」の列

「キー」と「値」の列が対応していれば列の順序は自由
また,「キー」が空の列は無視されるので,計算やメモの列を確保可能

正解と選択肢はいくつでも登録可能
例えば選択肢は
「choices1」「choices2」「choices3」「choices4」「choices5」,,,と増やす
「choices1」から詰めて入力

スクリプトエディタ起動

「ツール」→「スクリプト エディタ」
許可等求められた場合は適宜対応
image.png

上記スクリプトをコピペ,実行

「実行」を押して実行
ただし「デバッグ」の右隣が「myFunction」になっていることを確認
image.png

完成

「実行完了」が出たら完成
Googleドライブの”トップ”に出来ている
image.png

ポイント

"シート1"のところはシート名に合わせる

let sheet = SpreadsheetApp.getActive().getSheetByName('シート1');

最初にシート全体を読み込んで読み込み回数を減らす

let _sheet = sheet.getDataRange().getValues();

「getDataObjects関数(自作)」で「question」オブジェクトにする
for文では「of」を使用して「qestionList[i][5]」のようなわかりにくい表現を避ける

//問題データ
let questions = getDataObjects(_sheet[3], _sheet.splice(5, lastRow - 1));

//問題文・選択肢を作成
for (let question of questions) {
  ,,,
}

テキスト入力解答欄は addTextItem で作成
解答形式を指定する場合は createTextValidation を使用
以下は解答を数字に限定する例

item = form.addTextItem();
let textValidation = FormApp.createTextValidation()
  .setHelpText('数値で入力してください')
  .requireNumber()
  .build();
item.setValidation(textValidation);

問題順をランダムにするには setShuffleQuestions をtrueにする

let form = FormApp.create("title");
form.setShuffleQuestions(true);

問題点

  • 高速化したけど遅い(大量の問題を作る場合は結構待つ)
  • 自動生成では自由記述型の解答形式の問題に正答を設定できない(手動か選択型なら可能,参考

おわり

こんな感じです
お付き合いいただきありがとうございました
また,「スタディステーション」等についても記事にしていただきますので
今後ともよろしくお願いたします

あと,仕事ください

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3