モーリーのメモ

アプリ開発等(プログラミング、CG作成)、興味を持ったことを実践してまとめるブログです。

モーリーのメモ

HTMLテーブルタグをGoogleスプレッドシートで作る!(改良版)

今回は『Googleスプレッドシート』で表を作って

    f:id:mmorley:20191219200854p:plain
 ぽちっとすると
    f:id:mmorley:20191217223409p:plain
 HTMLのテーブルタグを作成できるようにします。
    f:id:mmorley:20191219200723p:plain:w550
 テーブルタグを記事に貼るとこんな感じです。
    グループ名前産地個数
    果物りんご青森6
    みかん
    (温州)
    和歌山2
    愛媛2
    野菜たまねぎ北海道12
 
 出来ることは以下のとおりです。
  • セルの結合を反映します。
  • 太字のセルを見出しセル(thタグ)にします。
  • 文字の色を再現します。
  • セルの背景色を反映します。※見出しセルは除きます。
  • 縦および横方向の文字寄せを反映します。
  • セル内の改行を反映します。
 
 下記の記事の改良版なのですが、一番の違いはセルの結合の自動判別です。 以前は『結合あり』を選ぶと、
    f:id:mmorley:20191217172303p:plain
 同じ文字が入ったセルを結合するというものでした。
    f:id:mmorley:20191217225235p:plain
 他にはセルの背景色を再現するようにしたため、通常セルと見出しセルの設定方法を変更しました。
  • 以前:背景色が白い外のセルを見出しセルにする
  • 今回:文字が太字のセルを見出しセルにする
 
 完全ではないですが、以前より『Googleスプレッドシート』で見たままに近いテーブルタグを作れるようになりました。
 
 それでは作り方を説明します。

使用環境

 私が使用している環境です。

設定方法

 Googleスプレッドシートは、無料で使えるオンラインの表計算(エクセルみたいな)アプリです。
 利用するにはgoogleアカウントが必要です。

新しいスプレッドシートを作成する

  1. 下記のサイトを開きます。
    Google Sheets: Free Online Spreadsheet Editor | Google Workspace
  2. 画面右下『+』をクリックします。
    f:id:mmorley:20191218094356p:plain
  3. 『無題のスプレッドシート』をクリックして、任意の名前を入力します。
    f:id:mmorley:20191218102745p:plain
    今回は”テーブルタグ作成”にしました。

スクリプトを作成する

  1. 『ツール』→『スクリプトエディタ』をクリックします。
    f:id:mmorley:20191218103903p:plain
  2. スクリプトエディタの『コード.gs』に最初からあるコードを全て削除します。
  3. 下記のコードをコピーして、『コード.gs』に貼り付けます。

    // テーブルタグ作成関数を実行
    function runCreateTableTag() {
      createTableTag(); // テーブルタグを作成する
    }
    
    // テーブルタグ作成関数
    function createTableTag() {
      var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); // アクティブシート
      var range = sheet.getDataRange(); // データのある範囲
      var numRows = range.getNumRows(); // データのある行数
      var numCols = range.getNumColumns(); // データのある列数
      var cells = range.getValues(); // データの配列
      var tableTag = "<table>"; // テーブルタグを格納する
    
      // セルの結合の有無と表示値を取得する
      var mcell = new Array(numRows); // セルの結合の有無を格納する配列を作成、true:結合有り
      var vcell = new Array(numRows); // 結合セルの表示値を格納する配列を作成
      for(var i = 0; i < numRows; i++){ // 行数分ループ
        mcell[i] = new Array(numCols); // 2次元配列を作成
        vcell[i] = new Array(numCols); // 2次元配列を作成
        for(var j = 0; j < numCols; j++){ // 列数分ループ
          var mrange = sheet.getRange(i+1, j+1, 1, 1); // セルを取得
          mcell[i][j] = mrange.isPartOfMerge(); // 結合の有無を取得
          if(mcell[i][j]){ // 結合有りの場合
            vcell[i][j] = mrange.getMergedRanges()[0].getDisplayValue(); // 表示値を取得
          }
        }
      }
      
      // テーブルタグを作成する
      for(var i = 0; i < numRows; i++){ // 行数分ループ
        var rowTag = "<tr>"; // 行タグを格納する
        for(var j = 0; j < numCols; j++){ // 列数分ループ
          var margeString = ""; // セル結合の属性値を格納する
          // 行方向で、先頭でない結合セルの場合はスキップする
          if(i > 0){ // 先頭の行でない場合
            if(mcell[i-1][j] && mcell[i][j] && vcell[i-1][j] === vcell[i][j] && cells[i][j] === ""){ // 1つ上のセルと現在のセルが結合セル&表示値が同じ&現在のセルの値が空白の場合
              continue; // 以下の処理をスキップする
            }
          } 
          // 列方向で、先頭でない結合セルの場合はスキップする
          if(j > 0){ // 先頭の列でない場合
            if(mcell[i][j-1] && mcell[i][j] && vcell[i][j-1] === vcell[i][j] && cells[i][j] === ""){ // 1つ左のセルと現在のセルが結合セル&表示値が同じ&現在のセルの値が空白の場合
              continue; // 以下の処理をスキップする
            }
          } 
          // 行方向のセルの結合数をカウントする
          var count = 1; // 結合数
          for(var k = i + 1; k < numRows; k++){ // 最終行までループ
            if(mcell[k-1][j] && mcell[k][j] && vcell[k-1][j] === vcell[k][j] && cells[k][j] === ""){ // 先頭ではない結合セルの場合
              count ++; // カウントアップ
            }else{ // それ以外の場合
              break; // カウントを終了する
            }
          }
          if(count > 1){ // 結合数が1より大きい場合
            margeString += ' rowspan="' + count.toString() + '"'; // テーブルタグの行結合の属性値を作成する
          } 
          // 列方向のセルの結合数をカウントする
          count = 1; // 結合数
          for(var k = j + 1; k < numCols; k++){ // 最終列までループ
            if(mcell[i][k-1] && mcell[i][k] && vcell[i][k-1] === vcell[i][k] && cells[i][k] === ""){ // 先頭ではない結合セルの場合
              count ++; // カウントアップ
            }else{ // それ以外の場合
              break; // カウントを終了する
            }
          }
          if(count > 1){ // 結合数が1より大きい場合
            margeString += ' colspan="' + count.toString() + '"'; // テーブルタグの列結合の属性値を作成する
          }
          // 通常・見出しセル、セルの背景色、文字色を設定する
          var cellTag = ""; // セルタグ
          var colorString = ""; // 背景色指定の属性値
          if(range.getFontWeights()[i][j] === "normal"){ // 文字が通常の場合(太字でない場合)
            cellTag = "td" // 通常のセル
            if(range.getBackgroundColors()[i][j] !== "#ffffff"){ // 白色の場合
              colorString = ' bgcolor="' + range.getBackgroundColors()[i][j] + '"'; //色指定の属性値を追加する
            }
          }else{ // それ以外の場合
            cellTag = "th"; // 見出しセル
          }
          rowTag += "<" + cellTag + margeString + colorString; // セルの結合と背景色指定を追加する
          if(range.getFontColors()[i][j] !== "#000000"){ // 文字が黒でない場合
            rowTag += ' style="color:' + range.getFontColors()[i][j] + '"'; // 文字色指定を追加する
          }
          
          // 横方向の文字寄せ
          var alignString = range.getHorizontalAlignments()[i][j].replace("general-", ""); // スプレッドシートのセルの文字寄せの状態を取得する
          switch(alignString){ // 文字寄せの種類別処理
            //case "left": // 左寄せ テーブルタグのセルのデフォルト位置なので記述しない
            case "center": // 中央寄せ
            case "right": // 右寄せ
              rowTag += ' align="' + alignString + '"'; // テーブルタグの文字寄せの属性値を作成
              break;
          }
          
          // 縦方向の文字寄せ
          var alignString = range.getVerticalAlignments()[i][j]; // スプレッドシートのセルの文字寄せの状態を取得する
          switch(alignString){ // 文字寄せの種類別処理
            case "top": // 上寄せ
            //case "middle": // 中央寄せ(縦)テーブルタグのセルのデフォルト位置なので記述しない
            case "bottom": // 下寄せ
              rowTag += ' valign="' + alignString + '"'; // テーブルタグの文字寄せの属性値を作成する
              break;
          } 
          
          rowTag += ">"; // 開始側のセルタグを閉じる
          rowTag += range.getDisplayValues()[i][j].replace(/\n/g, "<br>") + "</" + cellTag + ">"; // セルの中身と終了側のセルタグを追加する(改行は改行タグに変換する)
        }
        rowTag +="</tr>"; // 行タグを閉じる
        tableTag += rowTag; // テーブルタグに行タグを追加する
      }
      tableTag += "</table>"; // テーブルタグを閉じる
      
      Browser.msgBox(tableTag); // メッセージボックスにテーブルタグ出力
    }
    
    // シートの書式・値を全削除する
    function clearSheet() {
      SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().clear(); // アクティブシートをクリア
    }
    
    // スプレッドシートの起動時にメニューに追加する
    function onOpen(){ 
      var ssheet = SpreadsheetApp.getActiveSpreadsheet(); // アクティブシート
      
      var menu = [{name: '実行', functionName: 'runCreateTableTag'}]; // メニューの項目を作成する      
      ssheet.addMenu('テーブルタグ作成', menu); // メニューを作成する
      
      menu = [{name: '実行', functionName: 'clearSheet'}]; // メニューの項目を作成する
      ssheet.addMenu('シートをクリア', menu); // メニューを作成する     
    }
    

  4. 『保存』ボタンをクリックします。
    f:id:mmorley:20191218112424p:plain
  5. 任意のプロジェクト名を入力して、『OK』をクリックします。
    f:id:mmorley:20191218112643p:plain
    今回は”テーブルタグ作成”にしました。

スプレッドシートにメニューを追加する

  1. 実行』→『関数を実行』→『onOpen』をクリックします。
    f:id:mmorley:20191219104751p:plain
  2. 『許可を確認』をクリックします。
    スクリプトを初めて実行する際には、自作のものでも承認が必要です。
    [f:id:mmorley:20191219105402p:plainw500]
  3. アカウントを選択します。
    f:id:mmorley:20191219111202p:plain:w500
  4. 『詳細』をクリックします。
    『安全なページに戻る』をクリックすると、スクリプトを実行せずにスプレッドシートに戻ります。
    f:id:mmorley:20191219111341p:plain
  5. ウィンドウを下に広げて『無題のプロジェクト(安全ではないページ)に移動』をクリックします。
    『安全ではないページ』という表現に不安になりますが、『スクリプトを実行しますけど良いですか?』という確認の意味です。
    f:id:mmorley:20191219112131p:plain:w500
  6. 『許可』をクリックします。
    f:id:mmorley:20191219112440p:plain:w500
    スプレッドシートのメニューに『テーブルタグ作成』と『シートをクリア』が追加されます。
    f:id:mmorley:20191219114438p:plain
 設定は以上です。

使い方

  下記の手順でテーブルタグを作成します。

  1. スプレッドシートで表を作成します。
    f:id:mmorley:20191219172017p:plain
  2. 『テーブルタグ作成』→『実行』をクリックします。
    f:id:mmorley:20191219172342p:plain
  3. 少し待つとテーブルタグが表示されるので、範囲選択してコピーします。
    表の行数と列数が増えると処理時間が長くなります。
    f:id:mmorley:20191219172623p:plain
  4. テーブルタグを貼り付けます。
    グループ名前産地個数
    果物りんご青森6
    みかん
    (温州)
    和歌山2
    愛媛2
    野菜たまねぎ北海道12
  5. スプレッドシートから表を削除するには『シートクリア』→『実行』をクリックします。
    f:id:mmorley:20191219173005p:plain

補足

  • 値の入った範囲がテーブルタグになります。
  • 見出しセル(thタグ)にしたいセルを太字にします。
    ※セル自体を選択して太字にします。中の文字ではありません。
  • はてなブログでは見出しセルに背景色が設定出来ないため、見出しセルに背景色の設定をしていません。
  • 下図の結合セルは再現出来ません。
    『結合セルの先頭以外のセルが接している』かつ『文字が同じ』場合です。
    水色の部分が再現出来ません。
    f:id:mmorley:20191219183018p:plain
    下表のようになります。
    りんごりんご
    りんご
    りんご
    内部的に下図のように検出するためです。
    f:id:mmorley:20191219191956p:plain
    文字が異なれば、正しく表示されます。
    りんごりんご
    りんご
    みかん
    同じ文字にしたい場合は『空白文字(スペース)』を使用して下さい。

あとがき

 スプレッドシートのセルの結合を判別する関数を見つけたので、以前作ったスクリプトを改良してみました。ですが、その関数の処理時間が長いために全体の実行時間は長くなっています。
 以前作ったスクリプトは『並んだ同じ文字のセル』を自動で結合するので用途に合わせて使って下さい。