コモノExtendScript100本ノック

超初心者のDTPオペレーターが週にひとつスクリプトを書くブログ

061.【Id】タブ区切りtxtを読み込んで一括検索置換2

挙動

  1. あらかじめ以下のようなテキストデータを作成しておく
    検索ワード1[タブ]置換ワード1
    検索ワード2[タブ]置換ワード2
  2. 起動時に上記テキストを指定する
  3. 正規表現かテキスト検索か、②どこを検索範囲とするか を選択する
  4. 実行ボタンを押すと、検索ワード1の検索結果のうち1つ目が置換ワード1に置換される

目次のノンブルの修正指示が手書きで来た時のために書いた。

コード

//@targetengine "findChangeBatch2"

/* 
あらかじめ以下のようなテキストデータを作成する。
aaa[タブ]bbb
ccc[タブ]ddd
*/

var main = function() {
    app.scriptPreferences.enableRedraw = false;

    // 検索置換内容を取得
    var findWhatList = [];
    var changeToList = [];
    var txtObj = File("~/Desktop").openDlg("テキストを指定してください", "*.txt");
    if (!txtObj.exists) {
        alert("中断しました。");
        exit();
    } else {
        txtObj.open("r");
        var t = txtObj.read();
        var pairsList = t.split(/\r\n|\r|\n/);
        var pairsListCnt = pairsList.length;
        for (var i = 0; i < pairsListCnt; i++) {
            findWhatList.push(pairsList[i].split(/\t/)[0]);
            changeToList.push(pairsList[i].split(/\t/)[1]);
        }
      if (findWhatList.length!==changeToList.length){
        alert("読み込みテキストに不備があります。\n中断します。");
        exit();
        }
    }

    // 検索範囲のリストを生成
    var tgtDispName = ["ドキュメント"];
    if (app.activeDocument.selection.length > 0) {
        var sel = app.activeDocument.selection;
        for (var i = 0; i < sel.length; i++) {
            if (sel[i].constructor.name === "TextFrame") {
              if (sel.length>1){
                alert ("複数のテキストフレームには未対応です。\n中断します。");
                exit();
                } else {
                tgtDispName.push("ストーリー");
                break;
                }
            } else if (sel[i].constructor.name === "Character" ||
                sel[i].constructor.name === "Word" ||
                sel[i].constructor.name === "Line" ||
                sel[i].constructor.name === "TextColumn" ||
                sel[i].constructor.name === "Paragraph" ||
                sel[i].constructor.name === "TextStyleRange"||
                sel[i].constructor.name === "Text" ) {
                tgtDispName.push("選択範囲");
            }
        }
    }

    // ウィンドウ生成
    var dialog = new Window("dialog");
    dialog.text = "一括検索置換";
    dialog.orientation = "row";
    dialog.alignChildren = ["left", "top"];

    var group1 = dialog.add("group");
    group1.orientation = "row";
    group1.alignChildren = ["left", "top"];

    var panel1 = group1.add("panel", undefined);
    panel1.text = "検索";
    panel1.orientation = "column";
    panel1.alignChildren = ["left", "top"];

    var statictext1 = panel1.add("statictext", undefined, undefined, {
        multiline: true
    });
    statictext1.text = findWhatList.join("\n");
    statictext1.preferredSize.width = 150;
    statictext1.preferredSize.height = 100;

    var panel2 = group1.add("panel");
    panel2.text = "置換";
    panel2.orientation = "column";
    panel2.alignChildren = ["left", "top"];

    var statictext2 = panel2.add("statictext", undefined, undefined, {
        multiline: true
    });
    statictext2.text = changeToList.join("\n");
    statictext2.preferredSize.width = 150;
    statictext2.preferredSize.height = 100;

    var group2 = dialog.add("group");
    group2.orientation = "column";
    group2.alignChildren = ["fill", "top"];
    group2.spacing = 20;
    group2.margins = 0;

    var group3 = group2.add("group");
    group3.orientation = "column";
    group3.alignChildren = ["left", "top"];
    group3.margins.top = 10;

    var checkbox1 = group3.add("checkbox");
    checkbox1.text = "正規表現";
    checkbox1.preferredSize.width = 100;
    checkbox1.alignment = ["center", "top"];

    var statictext3 = group3.add("statictext");
    statictext3.text = "検索置換範囲:"
    var dropdown1 = group3.add("dropdownlist", undefined, tgtDispName);
    dropdown1.preferredSize.width = 100;

    var button1 = dialog.add("button")
    button1.text = "実行";
    button1.onClick = function() {
        dialog.close(1);
    }
    var dlgResult = dialog.show();
    if (dlgResult !== 1) {
        alert("中断しました。");
        exit();
    }


    // 検索範囲を取得
    if (!dropdown1.selection) { 
        alert("検索置換範囲が選択されていないため、中断しました。");
        exit();
    } else if (dropdown1.selection.text === "ドキュメント") {
        var tgt = [app.activeDocument];
        var cnt = 1;
    } else {
        var tgt = sel;
        var cnt = tgt.length;
    }
    for (var i = 0; i < cnt; i++) {
        for (var j = 0; j < pairsListCnt; j++) {
            // 正規表現 or テキスト検索
            if (checkbox1.value) {
                if (tgt[i].hasOwnProperty("changeGrep")) {
                    myFindGrep(tgt[i], findWhatList[j]).contents = changeToList[j];
                }
            } else {
                if (tgt[i].hasOwnProperty("changeText")) {
                    myFindText(tgt[i], findWhatList[j]).contents = changeToList[j];
                }
            }
        }
    }
    alert("完了しました。");



    function myFindGrep(tgt, rgx) {
        app.findGrepPreferences = NothingEnum.NOTHING;
        app.findGrepPreferences.findWhat = rgx;
        var result = tgt.findGrep()[0];
        app.findGrepPreferences = NothingEnum.NOTHING;
        return result;
    }

    function myFindText(tgt, str) {
        app.findTextPreferences = NothingEnum.NOTHING;
        app.findTextPreferences.findWhat = str;
        var result = tgt.findText()[0];
        app.findGrepPreferences = NothingEnum.NOTHING;
        return result;
    }

}

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.FAST_ENTIRE_SCRIPT, "findChangeBatch2.jsx");

メモ

分かったこと

var txtObj = File("~/Desktop").openDlg("テキストを指定してください", "*.txt");
if (!txtObj) {
    alert("中断しました");
    exit();
}
// --> 存在しないテキストを指定しても、スルーして次の処理に行ってしまう

存在していなくても、(!○○)で拾えない場合がある。
例えばparagraphStyles.itemByName("ないよー")は「ないよー」スタイルが無かったとしてもundefinedにはならない。
存在の確認をしたい場合は、
- テキストなどFileオブジェクトの場合はexistsプロパティを見る。
- activeDocumentの場合はapp.documents.lengthを見る。
- そのほかの場合は…try~catchするとか?

参考