InDesign JavaScript ファイルから索引

ファイルから索引を作成するスクリプトは、これで良いのかな・・・？

~~~JavaScript
/*
このスクリプトを利用して起こった不具合の責任は取れません。
ご了承下さい。

更新 2021/11/12
*/

// アプリ指定
#target "indesign";

// スクリプト名
var scriptName = "ファイルから索引";

//スクリプトの動作指定（一つのアンドゥ履歴にする、及び、アンドゥ名）
app.doScript(function(){

    // 分割文字
    var splitText = ",";

    // ダイアログ
    var dialogueFlg = confirm("アクティブドキュメントにテキストまたはCSVのファイルから索引の見出しと参照を作成します。" + "\r\r"
    + "参照の検索文字列（正規表現）は「"+ splitText + "」で区切られた9番目になります。" + "\r"
    + "9番目が空白の場合は最下層の項目が参照の検索文字列になります。" + "\r\r"
    + "「検索と置換」の　『正規表現』　での検索の「検索形式」の入力での検索も可能です。"+ "\r\r"
    + "追加する参照が既存の参照と重複する場合は追加しません。" + "\r\r"
    + "ファイルの例（一行目は利用しません）" + "\r"
    + "項目1,読み,項目2,読み,項目3,読み,項目4,読み,参照の検索文字列" +"\r"
    + "動物,どうぶつ,猫,ねこ,三毛（日本固有種）,みけ（にほんこゆうしゅ）,,,三毛" +"\r"
    + "Id,インデザイン" +"\r"
    + "adobe"
    ,"", scriptName);

    // Noの場合
    if(dialogueFlg == false){

        // 終了
        exit();
    }

    /* 検索文字列以外を使う場合の処理 */
    // 正規表現の検索プロパティのフラグ
    var findGrepPreferencesPropertyFlg = false;

    // 検索形式一覧
    var findFormatList = [];

    // 正規表現の検索のプロパティ名の数だけ変数に入れて繰り返す
    for(var findGrepPreferencesProperty in app.findGrepPreferences.properties){

        // プロパティ名が「findWhat」、「parent」、「bulletChar」、「numberingRestartPolicies」では無い場合
        if(findGrepPreferencesProperty != "findWhat" && findGrepPreferencesProperty != "parent" && findGrepPreferencesProperty != "bulletChar" && findGrepPreferencesProperty != "numberingRestartPolicies"){

            // プロパティの内容が「NothingEnum.NOTHING」、「」、「null」ではない場合
            if(app.findGrepPreferences[findGrepPreferencesProperty] != NothingEnum.NOTHING && app.findGrepPreferences[findGrepPreferencesProperty] != "" && app.findGrepPreferences[findGrepPreferencesProperty] != null){

                findGrepPreferencesPropertyFlg = true;

                // 検索形式を集める
                findFormatList.push(findGrepPreferencesProperty + ":" + app.findGrepPreferences[findGrepPreferencesProperty]);
            }
        }
    }
    /* ここまで */

    // 索引が無い場合
    if(app.activeDocument.indexes.count() == 0){

        // 索引を作成
        app.activeDocument.indexes.add();
    }

    // テキスト検索の初期化
    app.findTextPreferences = NothingEnum.NOTHING;

    // 見出しの最初の数
    var firstTopicNumber = searchTopicNumber(app.activeDocument.indexes.firstItem(),0);

    // テキストファイル読み込みダイアログ
    var openFile = File.openDialog("索引を作成する為のテキストファイルを指定して下さい。","*.txt,*.csv");

    // 読み込むファイルの確認
    if(openFile){

        // ファイルオブジェクト作成
        fileObject = new File(openFile);

        // 読み込み
        var openFlg = fileObject.open("r");

        // 進行状況のパレット
        var processingPalette = new Window("palette", "進行状況", undefined, {closeButton: false});
        processingPalette.orientation = "column";
        processingPalette.alignChildren = ["left","top"];
        processingPalette.spacing = 5;
        processingPalette.margins = 10;
        
        // 子階層のパネル
        var processingPanel = processingPalette.add("panel", undefined, undefined,); 
        processingPanel.text = "参照検索（正規表現）"; 
        processingPanel.preferredSize.height = 80; 
        processingPanel.orientation = "column"; 
        processingPanel.alignChildren = ["left","top"]; 
        processingPanel.spacing = 5; 
        processingPanel.margins = 10;

        // パネルの文章
        var paletteSearchText = processingPanel.add("statictext", [0, 0, 570, 15], undefined);
        processingPanel.add("statictext", undefined, "検索形式 ： " + findFormatList.join(" + "));
        var paletteProcessingText = processingPanel.add("statictext", [0, 0, 570, 15], undefined);

        // パレットの文章
        processingPalette.add("statictext", [0, 0, 0, 5], undefined);
        processingPalette.add("statictext", undefined, "「Esc」キーでスクリプトを取消し出来ます（Macは不明）。");
        processingPalette.add("statictext", [0, 0, 0, 5], undefined);
        processingPalette.add("statictext", [0, 0, 595, 55], "処理で文字を選択します。" + "\r"
        + "ドキュメントウィンドウの最小化（「ウィンドウメニュー」>「アレンジ」>「ウィンドウを分離」の後、「ウィンドウメニュー」>「アレンジ」>「最小化」）や各種パネルを閉じておくのをおすすめします。"
        ,{multiline: true});

        // 表示
        processingPalette.show();

        // ファイルが開けた場合
        if (openFlg == true){

            // 検索結果
            var grepResult;

            // 一行分の文字
            var lineText = "";

            // 検索文字
            var searchText = "";

            // 分割後の文字配列
            var splitTextArray;

            // 新規見出し
            var newTopic;

            // 見出し階層数
            var topicHierarchyNumber = 0;

            // 新規参照
            var newReference;

            // 参照追加数
            var referenceNumber = 0;

            // 行数
            var lineNumber = 0;

            // 新規の参照が作成される前の検索結果の最初の挿入点のＩｎｄｅｘ
            var previousReferenceFirstInsertionPointsIndex;

            // 対象の文字
            var targetCharacter;

            // 対象のＩｎｄｅｘ
            var targetIndex;

            // 項目数
            var topicNmuber = 0;

            // 検索結果数
            var searchNumber = 0;

            // 最後の行まで繰り返す
            while (!fileObject.eof){

                // 初期化
                topicHierarchyNumber = 0;

                // 一行読み込み
                lineText = fileObject.readln();

                // 増やす
                lineNumber++;

                // 一行目の場合
                if(lineNumber == 1){

                    // 次の繰り返しへ
                    continue;
                }

                // 分割文字で分割
                splitTextArray = lineText.split(splitText);

                // 項目1が空白で無い、かつ、分割の数が9以下の場合
                if(splitTextArray[0] != "" && splitTextArray.length <= 9){

                    // 増やす
                    topicNmuber++;

                    // 初期化
                    newTopic = app.activeDocument.indexes.firstItem();

                    // 項目の数だけ繰り返す
                    for(var i = 0; i <= splitTextArray.length - 1 && i < 8; i += 2){

                        // 初期化
                        searchText = "";

                        // 索引項目（見出し）が空白で無い場合
                        if(splitTextArray[i] != ""){

                            // 入れる
                            topicReading = splitTextArray[i + 1];          

                            // エラー処理
                            try{

                                // 見出し作成
                                newTopic = newTopic.topics.add(splitTextArray[i],splitTextArray[i + 1]);

                            // エラーの場合
                            }catch(e){

                                // 警告
                                alert("見出しが作成出来ませんでした。" + "\r" + "「索引」ウィンドウの「ソートオプション...」メニューを確認して下さい。");

                                // 繰り返しから抜ける
                                break;
                            }

                            // 見出しの階層数を増やす
                            topicHierarchyNumber++;
                        }
                    }

                    // 分割が9つ有る場合
                    if(splitTextArray.length == 9){

                        // 入れる
                        searchText = splitTextArray[8];

                    // 以外の場合
                    }else{

                        // 最下層の項目部分の分割を入れる
                        searchText = splitTextArray[topicHierarchyNumber * 2 - 2];
                    }   

                    // 検索文字文字列、もしくは、検索形式が有る場合
                    if(searchText != "" || findGrepPreferencesPropertyFlg == true){

                        // 検索文字列
                        app.findGrepPreferences.findWhat = searchText;

                        // 処理中表示
                        paletteSearchText.text = "検索文字列 ： " + searchText;
                        paletteProcessingText.text = "進行状況 ： 項目:" + topicNmuber + " 検索結果:0";

                        // ドキュメント全体から検索
                        grepResult = app.activeDocument.findGrep();

                        // 検索結果の数だけ繰り返す
                        grepResultLabel:
                        for(var i = 0; i < grepResult.length; i++){

                            // 入れる
                            searchNumber = i + 1;

                            // 処理中表示
                            paletteProcessingText.text = "進行状況 ： 項目:" + topicNmuber + " 検索結果:" + searchNumber;

                            // 検索結果を選択
                            grepResult[i].select();

                            // 選択の最初の挿入点のＩｎｄｅｘを入れる（参照を作成するとＩｎｄｅｘが変化するので）
                            previousReferenceFirstInsertionPointsIndex = app.activeDocument.selection[0].insertionPoints.firstItem().index;

                            // 参照形式を指定して参照作成
                            newReference = newTopic.pageReferences.add(grepResult[i],PageReferenceType.CURRENT_PAGE);

                            // 参照の位置がずれる場合（バグ？）
                            if(previousReferenceFirstInsertionPointsIndex != newReference.sourceText.index){

                                // 参照の挿入点を移動させる
                                newReference.sourceText.parent.characters.item(newReference.sourceText.index)
                                .move(LocationOptions.BEFORE,newReference.sourceText.parent.characters
                                .item(newReference.sourceText.index + previousReferenceFirstInsertionPointsIndex - newReference.sourceText.index));
                            }

                            // 追加
                            referenceNumber++;

                            /* 重複しているか */
                            // 対象のＩｎｄｅｘ
                            targetIndex = newReference.sourceText.index;

                            // 最初の挿入点では無い場合
                            if(targetIndex != 0){

                                // 前に調べていく
                                while(targetIndex >= 0){

                                    // 減らす
                                    targetIndex--;

                                    // 対象の文字
                                    targetCharacter =newReference.sourceText.parent.characters.item(targetIndex);

                                    // 検索文字列
                                    app.findTextPreferences.findWhat = "^I";

                                    // 索引マーカーが検索された場合
                                    if(targetCharacter.findText().length > 0){

                                        // 追加した参照のひとつ前から前に繰り返す
                                        for(var ii = newReference.parent.pageReferences.count() - 2; ii >= 0; ii--){

                                            // 対象のマーカーの挿入点が新規追加した参照の目次の参照の挿入点と同じ場合
                                            if(targetCharacter.insertionPoints.firstItem() == newReference.parent.pageReferences.item(ii).sourceText){

                                                // 参照を削除
                                                newReference.remove();

                                                // 減らす
                                                referenceNumber--;

                                                // ラベルの次の繰り返しへ
                                                continue grepResultLabel;
                                            }
                                        }
                                    }

                                    // 検索文字列
                                    app.findTextPreferences.findWhat = "^a";

                                    // アンカー付きオブジェクトマーカーが検索された場合
                                    if(targetCharacter.findText().length > 0){

                                        // 次の繰り返しへ
                                        continue;
                                    }

                                    // 抜ける
                                    break;
                                }
                            }
                            /* ここまで */

                        }
                    }
                }
            }

            // ファイルを閉じる
            fileObject.close();

        // 開けなかった場合
        }else{

            // 警告
            alert("ファイルが開けませんでした。");
        }

    // キャンセルの場合
    }else{

        // 終了
        exit();
    }

    // 索引の更新
    app.activeDocument.indexes.firstItem().update();

    // 初期化
    app.findTextPreferences = NothingEnum.NOTHING;
    app.findGrepPreferences.findWhat = NothingEnum.NOTHING;

    // 選択の解除
    app.activeDocument.selection = NothingEnum.NOTHING;

    // 見出しの追加数
    var additionalTopicNumber = searchTopicNumber(app.activeDocument.indexes.firstItem(),0) - firstTopicNumber;

    // 結果
    alert("見出し追加数:" + additionalTopicNumber + "\r"
    + "参照追加数:" + referenceNumber);

//スクリプトの動作指定の続き
}, ScriptLanguage.JAVASCRIPT, [scriptName], UndoModes.ENTIRE_SCRIPT, scriptName);

// 見出しの数検索用
function searchTopicNumber(targetTopic,topicNumber){

    // 見出しの数だけ繰り返す
    for(var i = 0; i < targetTopic.topics.count(); i++){

        // 数を追加
        topicNumber++;

        // 循環
        topicNumber = searchTopicNumber(targetTopic.topics.item(i),topicNumber);
    }

    // 数を返す
    return topicNumber;
}
~~~