[sh, js] 全角を 2 文字、半角を 1文字とカウントし、指定文字数ごとに区切り文字を挿入するスクリプトを作りました
2017/09/23 13:23
  • シェルスクリプト、 Google Apps Script を使って「全角を 2 文字、半角を 1文字とカウントし、指定文字数ごとに区切り文字を挿入するスクリプト」を実装しました。

    経緯

    とあるマスタデータのフィールドに、指定文字数ごとに "\n" を挿入していく事案が発生しました。笑
    ここで言う「文字数」とは、 JavaScript でよくある、「全角だろうが半角だろうが 1 文字は 1 文字!」ではなく、
    「全角は 2 文字、半角は 1 文字」とした文字数です。(そのテキストは等幅フォントで表示しており改行位置が揃うようになるため)

    依頼を受けた時点では少なくとも過去分だけ対応すればよかったので、その時点で入力済みデータをぼく(開発側)のほうでシェルスクリプトで対応してしまっていました。さらに、未来のデータ入力については、「担当者がよしなに頑張ってくれるだろう」と
    ぼくは何も考えていませんでした。笑

    結局のところ、入力ミスを防ぐため、「データ入力時にも改行コードを自動的に挿入してあげてほしい」という話になったので、
    あとから Google Apps Script で同様の処理をするツールを作ることになってしまったわけです。(;´Д`)
    こんなことなら最初から GAS で対応しておけばよかった。笑

    前段が長くなりましたが、本題です!(短い)

    シェルスクリプト版

    シェルスクリプトに関してはそれほど迷うところはなかったです。
    美しいコードではないので改善の余地は有ると思いますが、まあ要件は満たしてるので今回は良しということで。苦笑

    #!/bin/bash
    if [ $# != 2 ]; then
        echo "usage: $0 file_name char_max_length" 1>&2
        exit 0
    fi
    
    dir=`dirname $1`
    file_name=`basename $1`
    temp_csv_file="temp_${file_name}"
    char_max_length=$2
    rm -f ${temp_csv_file}
    
    cat "${dir}/${file_name}" | while read line
    do
      text=`echo $line | cut -d"," -f3|tr -d " "`
      if [ "$description" ]; then
        new_line=`echo ${line} | tr -d " "`
        # text を指定文字数で分割してタブでつなげる
        new_text=`echo "${text}" | fold -${char_max_length} | paste -s -d "\t" -`
        # 一旦ファイルに書き出し
        echo "${new_line}" | sed -e "s/${text}/${new_text}/g" >> ${temp_csv_file}
      else
        echo "${line}" >> ${temp_csv_file}
      fi
    done
    
    # タブを \n に置換する
    # 「\n」の文字列をつけるのが難しかったので苦肉の策
    sed -i -e "s/\t/\\\n/g" ${temp_csv_file}
    
    というわけで、内容重複しますが github のこのページにて公開していますのでご自由にお使い下さい。
    もろもろの説明は README に書いているのでそちらを参照して下さい。m(_ _)m
    きっと弊社の黒魔術師なら10行くらいに圧縮してくれるんだろうなぁ…なんて考えて虚しくなる毎日ですね。
    (↑これはシェルスクリプト書くたびに思うw)


    Google Apps Script 版

    GAS 版ですが、Google Spread Sheet を利用しました。
    ・セルに文章を入力すると、すぐ右のセルに改行コードが追加された文章がペーストされます。
    ・複数行同時入力(まとめてペーストとか)にも対応しており、 "Convert" ボタンをクリックするだけで OK です。

    // attach "\n" string into each N charactors
    var char_length = 20;
    
    // Execute "onEdit()" after spread sheet has been changed.
    function onEdit(e) {
      var current_sheet = e.source.getActiveSheet();
      var row = e.range.getRow();
      var col = e.range.getColumn();
      var cell_value = e.value;
      var old_value = e.oldValue;
      
      if (row !== 1 && col == 2) {
        var range = current_sheet.getDataRange();
        var text = "";
        if (old_value !== "") {
          var str_arr = splitStringsByLength(cell_value, char_length);
          text = str_arr.join('\\n');
        }
        range.getCell(row, col + 1).setValue(text);
      }
    }
    
    // Execute after clicked "Convert" button.
    function convertAll() {
      var sheet = SpreadsheetApp.getActiveSpreadsheet();
      var current_sheet = sheet.getActiveSheet();
      var range = current_sheet.getRange(2, 2, current_sheet.getMaxRows() - 1);
      var values = range.getValues();
      
      var pasted_range = current_sheet.getRange(2, 3, current_sheet.getMaxRows() - 1);
      for (var row in values) {
        var orig_text = values[row][0];
        var str_arr = splitStringsByLength(orig_text, char_length);
        var text = str_arr.join('\\n');
        pasted_range.getCell(parseInt(row, 10) + 1, 1).setValue(text);
      }
    }
    
    function splitStringsByLength(text, length) {
      var text_array = text.split('');
      var count = 0;
      var str = '';
      
      var ret_text_array = [];
      
      for (i = 0, l = text_array.length; i < l; i++) {
        var n = escape(text_array[i]);
        
        if (n.length < 4) {
          count++;
        } else {
          count += 2;
        }
        
        if (count > length) {
          ret_text_array.push(str);
          count = 1;
          str = '';
        }
        
        str += text.charAt(i);
        
        if (i === text_array.length - 1) {
          ret_text_array.push(str)
        }
      }
      return ret_text_array;
    }
    

    シェルスクリプト版と同様に、 github のこのページにて公開していますのでご自由にお使い下さい。
    もろもろの説明は README に書いているのでそちらを参照して下さい。m(_ _)m

    人気ブログランキングへ ブログランキング・にほんブログ村へ
    ↑応援よろしくお願いします!m(_ _)m

  • <2017/09/23 13:23>
  • ツール
  • Java ScriptShell ScriptJSシェルスクリプトスクリプト便利ツールTool
  • 新しい記事へ
    [Mac] git コマンドを叩くと、ライセンスに同意するよう要求されたときの対応方法

    古い記事へ
    [所感] slack view optimizer の日別ユーザー数が100人を突破しました

profile picture

自己紹介的な何か

@wkmettyでついったーやってます。時々。 6年間勤めたゲーム会社を2018年2月に退職しフリーランスのプログラマに。 WordPress Core, WP-CLI コントリビューター。 お仕事募集中です。