最近、ある自動組版のプログラムを書いています。プログラムは大まかに2つの部分に分かれます。【1】は自動組版、【2】は組版後のInDesignデータを抽出し元の入稿データと比較するものです。自動組版する際、いくつかの外字を指定の字形に置換する必要があります、逆に、抽出する際、元に戻してから比較する必要があります。【1】と【2】の外字処理部分は共通のデータ(dictに定義)を使用しているため、このデータと他のいくつかの共通設定を、単独のjsxスクリプトに書き込んでからインポート(include)します。
ここで悪夢が始まります。
デバッグ中に、非常に妙な事が発生しました。
InDesign から抜き出したデータ(リスト)を csv に書き込むと、csv の総行数が常に list.length よりも3行少ないことがわかりました。調査の結果、足りない 3 行にはすべて外字が含まれていることがわかりました。
プログラムを最小限に抑えると、おおよそ次のようになります:
外字の置換リストは、myReplaceList.jsx ファイルに書かれています。

const replaceList = {
    "a": "あ",
    "吉野家": "𠮷野家",
    "i": "い",
    //他の置換対象...
}

その後、組版プログラム(仮に testScript.jsx とします)にこのファイルをインポートします。

#include myReplaceList.jsx
//
for (var k in replaceList) {
    $.writeln(k, ":", replaceList[k]);
}
//
writeTxtFile(replaceList);
//
function writeTxtFile(dict) {
    var fileObj = new File("~/Desktop/myReplaceList.txt");
    fileObj.encoding = "UTF-8";
    if (fileObj.open("w")) {
        for (var k in dict) {
            fileObj.writeln(k, ":", replaceList[k]);
        }
        fileObj.close();
    } else {
        alert("Failed to open data file.");
    }
}

コンソールに出力したり、txt ファイルに書き込んだりすると、次のようになります!1 行不足しています(replaceList辞書内の𠮷野家のデータが欠落しています)!


 

デバッグ中、replaceList は次のようになります。

𠮷野家の行を注釈してみたら、問題なくなる。

"Failed to retrieve variables" を検索しましたが、役立つ情報は見つかりませんでした。

さらに調査を進めるために(プログラムをさらに最小限にする)、myReplaceList.jsx の replaceList 変数を直接 testScript.jsx に書き込むと、次のようになります。

 

何の問題もありません。

ここまでで、1 日を費やしました。問題がなんとなくわかった:外字を外部jsxファイルに定義すると、includeする時に問題が発生する可能性があります。

原因を特定するために、再度調査範囲を縮小します。以下のコードを config.jsx ファイルに保存する。

const myChar = "𠮷";

メインの処理プログラムにconfig.jsxをinclude:

#include config.jsx
//外部で定義した変数を参照する
$.writeln("myChar: ", myChar);//なにも表示されない
$.writeln("myChar === 𠮷: ", myChar === "𠮷");//false
$.writeln("myChar.toSource(): ", myChar.toSource());//(new String("\uD842"))

myCharを直接にメインプログラム内部で定義する:

const myChar = "𠮷";
//本スクリプトで定義した変数を参照する
$.writeln("myChar: ", myChar);//myChar: 𠮷
$.writeln("myChar === 𠮷: ", myChar === "𠮷");//true
$.writeln("myChar.toSource(): ", myChar.toSource());//(new String("\uD842\uDFB7"))

この2つの結果を比較してみたら、toSource()の結果に注目すようようになった。外部jsxをincludeする際、サロゲートペア文字について、なぜか後半のサロゲート(今回の例だと:\uDFB7)が無視されてしまう。この時点、直ぐにconfig.jsxをutf-16に再保存してみると、予想通りに問題消えた!(普段はvscode使っていて、defaultはutf-8なのです)

更に掘ってみると、下記のことに辿り着いた:
・外部jsxをutf-8で保存する場合、includeする際、サロゲートペア文字の後半サロゲートが無くなる。
・外部jsxをutf-16で保存する場合、問題ない。
・同じjsxファイル内で定義する場合、utf-8でも16でも問題ない。
※因みに、Pythonで試してみたが、問題ないです。(Pythonで自動組版する際、通常通り使えばいいです) 

結論:共通のjsxファイルを定義する際、utf-16で保存すると無難でしょう。

サロゲートペア文字