サポンテ 勉強ノート

サポンテの勉強ノート・読書メモなどを晒します。

Excel や Numbers からコピーした表を Markdown としてペーストする - その2【CotEditor】

はじめに

 先日 PHP で作成した CotEditor スクリプトを、pbpaste文字コード違いも気になったため JavaScript(JXA)で作り直しました。

使い方

 先日のスクリプト同様、表計算ソフトからセル範囲を選択して「コピー」を行います。

 CotEditor に戻って「⌘ + Shift + V」します。

 以下のようになります。

Id    |Name            |Price       
------|----------------|------------
1     |Apple           |200         
2     |Banana          |150         
3     |Citrus          |300         
九九九|ドラゴンフルーツ|価格未設定。

スクリプトソースコード

 ファイル名を「TSVを表としてペースト.@$v.js」などと設定し、CotEditor のスクリプトフォルダに入れれば、「⌘ + Shift + V」で実行できます。

#!/usr/bin/osascript -l JavaScript

(() => {
    'use strict';
    
    ObjC.import('stdlib')
    
    let CotEditor = Application('CotEditor');
    CotEditor.includeStandardAdditions = true;
    let doc = CotEditor.documents[0];
    const selection = doc.selection;
    
    const notification = (msg, title) => {
        let app = Application.currentApplication();
        app.includeStandardAdditions = true;
        app.displayNotification(msg, {
            withTitle: "CotEditor - スクリプト",
            subtitle: title,
            soundName: "Frog",
        });
    };
    
    const clipboardText = () => {
        let app = Application.currentApplication();
        app.includeStandardAdditions = true;
        return app.doShellScript("pbpaste");
    };
    
    const strlen = (str) => {
        // https://mebee.info/2020/12/21/post-26346/#outline__3
        let len = 0;
        for (let i = 0; i < str.length; i++) {
            (str[i].match(/[ -~]/)) ? len += 1 : len += 2;
        }
        return len;
    };
    
    const padright = (text, width, padString) => {
        let len = width - strlen(text);
        return text + padString.repeat(len);
    };
    
    let str = clipboardText();
    
    // 入力チェック
    if ((!str.includes("\r") || !str.includes("\n")) && !str.includes("\t")) {
        let msg = "改行/タブのいずれも含まれていないようです。";
        let title = "クリップボードの内容は TSV ではありません";
        notification(msg, title);
        $.exit(0);
    }

    // 行分割
    let linesSrc = str.split(/(\n|\r)+/);
    
    // 列分割
    let lines = [];
    linesSrc.forEach(line => {
        if (line.trim() === '') {return;}
        lines.push(line.trim().split("\t"));
    });
    
    // 列幅取得
    let colWidth = new Array(lines[0].length).fill(0);
    for (let i = 0; i < lines[0].length; i++) {
        lines.forEach(line => {
            let c = line[i];
            let w = strlen(c);
            colWidth[i] = Math.max(w, colWidth[i]);
        });
    }
    
    var ret = "";
    
    // 見出し出力
    let titles = [];
    lines[0].forEach((title, idx) => {
        titles.push(padright(title, colWidth[idx], ' '));
    });
    ret += titles.join("|") + "\n";
    
    // 水平線出力
    let hr = [];
    colWidth.forEach((w) => {
        hr.push("-".repeat(w));
    });
    ret += hr.join("|") + "\n";
    
    // データ部出力
    for (let row = 1; row < lines.length; row++) {
        let cols = [];
        lines[row].forEach((col, idx) => {
            cols.push(padright(col, colWidth[idx], ' '));
        });
        ret += cols.join("|") + "\n";
    }
    
    selection.contents = ret;
    CotEditor.activate();

})();

参考

 文字数のカウントに、以下のスクリプトを使わせていただきました。

javascript 全角文字は2文字で半角文字は1文字としてカウントする | mebee

環境

 以下の環境で開発・動作確認しました。

ProductName:   Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H1323
AppleScript version: 2.7
CotEditor version: 2.7.4
Numbers.app version: 10.3.9

 また、Google Spreadsheet でも確認しました。