秀丸マクロの配列のJavascriptとの受け渡No.10459
ラフ さん 24/09/13 13:45
 
1. 配列全体を渡すようになりませんか?
2. 配列の要素番号に変数を指定できるようになりませんか?

1.は
$$data[0] = "A";
$$data[1] = "B";
js {
 var tmp = hidemaru.getVar("$$data");
 tmp[1] = "C";
 hidemaru.setVar("$$data", tmp);
}
のような書き方。

2.は
$$data[0] = "A";
$$data[1] = "B";
##i = 1;
js {
 var tmp = hidemaru.getVar("$$data[##i]");
 hidemaru.setVar("$$data[##i]", "C");
}
のような書き方。

1.は大変かもしれないので、2.だけでも出来ませんでしょうか?

現状だと
$$data[0] = "A";
$$data[1] = "B";
##i = 1;
js {
 var i = hidemaru.getVar("##i");
 var tmp = hidemaru.getVar("$$data["+i+"]");
 hidemaru.setVar("$$data["+i+"]", "C");
}
するしかないですよね

==環境==
[Windows]
エディション:Windows 10 Pro 64bit
バージョン:22H2
OSビルド:19045.4894

[秀丸エディタ]
バージョン:9.37 64bit


[ ]
RE:10459 秀丸マクロの配列のJavascriptとNo.10460
こみやんま さん 24/09/13 17:19
 
■配列まるまるは難儀ですかねぇ。

配列全体といっても、秀丸マクロは配列の概念がしっかりしてないので、
長さがわからないんですよね。
配列中に0や""があった場合に、どこで終わりとみなすの? 問題が必ずでてきてしま
います。
(長さも渡すことになりますかねぇ...)


■getVarやsetVar 中に評価変数がある

getVarやsetVarに便乗するとhidemaruGlobalが遅くなるので、
以下みたいなのを作るのはありはありかなとは思いますね。
```
    var a = getEvalVar("$data[##b]");
    bool a = setEvalVar("$data[##b]", "aa");
```

とはいえ、これは、jsmodeのjavascriptで以下みたいな記述をすることとほとんど変
わりません。

```
function getEvalVar(expression) {
    if (expression[0] == '$' || expression[0] == '#') {
        var command = expression[0] + "_TEMP_GET_EVAL_VAR" + " = " + express
ion + ";";
        evalMacro(command);
        return getVar(expression[0] + "_TEMP_GET_EVAL_VAR");
    }

}

function setEvalVar(expression, value) {
    if (expression[0] == '$' || expression[0] == '#') {
        var command = expression + " = " + JSON.stringify(value) + ";";
        evalMacro(command);
    }

}

```


/// --------------------- 例 -------------------------

$x = "3";
##i = 20;
$data[##i] = "100";

js {

function getEvalVar(expression) {
    if (expression[0] == '$' || expression[0] == '#') {
        var command = expression[0] + "_TEMP_GET_EVAL_VAR" + " = " + express
ion + ";";
        evalMacro(command);
        return getVar(expression[0] + "_TEMP_GET_EVAL_VAR");
    }

}

function setEvalVar(expression, value) {
    if (expression[0] == '$' || expression[0] == '#') {
        var command = expression + " = " + JSON.stringify(value) + ";";
        evalMacro(command);
    }

}

message(getEvalVar("$data[##i]"));

setEvalVar("$data[##i]", "a\\\"bc");

}

message($data[##i]);

[ ]
RE:10460 秀丸マクロの配列のJavascriptとNo.10461
こみやんま さん 24/09/13 17:35
 
秀丸マクロ⇔jsmode だけではなく、
秀丸マクロ⇔秀丸マクロの橋渡し
などを考慮、
さらにはjsmodeが入ったことで json の取り扱いが多くなることを考慮して、

「秀丸マクロの変数⇔jsonへの変換関数」を 「秀丸マクロ層に用意」するのはあり
ではないかと思います。

■秀丸マクロ関数例。jsonへの変換とjsonからの復元を用意することで...
to_json_from_strvar($a);  JSON.stringifyと同じ結果。

to_json_from_numvar(#b);  JSON.stringifyと同じ結果。

to_json_from_arrvar($data, [長さ]); 長さはオプションなる。存在しなければ、文
字列配列なら""が、数値配列なら0が番兵となる。
配列をJSON.stringifyするのと同じ結果。


$a = to_strvar_from_json(json_string);

#b = to_numvar_from_json(json_string);

$data = to_arrvar_from_json(json_string); // この書き方は秀丸的にはダメかも。
to_arrvar_from_json(json_string, $data); // こちらが余儀なくされるかも。


■別マクロとの値渡しを型情報を失うことなく出来る。

この変換によって、JSONを介して、別のスクリプト空間へのやりとりが用意になる。
今まで数値・文字列・配列を別秀丸マクロへと送信すると値の型がつぶれてしまって
いたが
値の型を保持したまま文字列化と復元が出来るようになる。

よって

$data[0] = "abc";
$data[1] = "efg";

$arg = to_json_from_arrvar($data, 2); // 2はオプショナル

execmacro "別マクロ", $arg;

受信側マクロで、

to_arrvar_from_json($arg, $data); とすれば$dataの配列が一気に復元できる。


js {
    var jsonarr = getVar("$arg");
    var arr = JSON.parse(jsonarr);
    配列オブジェクトとして復元できる。
    arr[1] = "かきく";
    setVar("$json_src", JSON.stringify(arr));

}

to_arrvar_from_json($json_src, $data); // jsの配列が一気に秀丸マクロ配列とし
て構築できる



みたいな。

[ ]
RE:10459 秀丸マクロの配列のJavascriptとNo.10462
秀丸担当 さん 24/09/13 18:39
 
getVarやsetVarで配列をまるごと渡すということはできないです。
こみやんまさんも言われるように長さという概念が無かったりします。
json変換という案もありますが、似た方法としては、join関数とsplit関数で変換す
るといいかもしれません。
(文字列限定で、区切りは被らないものにする必要がありますが)

joinとsplitを使うようにしたとして、それが備え付けの関数だから高速というわけ
でもないです。
joinやsplit(あるいはjson案)はJavaScriptへの移行への一時的な使い方にとどめ
て、もし可能なら、ほぼ全てをJavaScriptに移行したほうが効率がいいかもしれませ
ん。

[ ]
RE:10462 秀丸マクロの配列のJavascriptとNo.10463
こみやんま さん 24/09/15 05:14
 
秀丸マクロは基本
・通常の数値型
・文字列型
・数値だけの配列(っぽい何か)
・文字列だけの配列(っぽい何か)

なので、
「配列自体」ではなく、「配列の要素」を取得したり設定したりするのをgetVarやse
tVarと同レベルでのネイティブ実装しておくのはありかも。
(getVarやsetVarに準ずる程度の速度があれば十分な気がします)

getVarやsetVarに対応する、

```


// 秀丸マクロ上のとある配列の要素を取得
function getArrayVarItem( arrayvar_name: string, index: number): string | nu
mber | null

// 秀丸マクロ上のとある配列の要素へ代入
function setArrayVarItem( arrayvar_name: string, index: number, value: strin
g|number): bool

```



// ---------------- 使用例 -----------------------


jsmode "WebView2";

$sdata[0] = "あいう";
$sdata[1] = "かきく";
$sdata[2] = "あいう";
$sdata[3] = "かきく";
$sdata[4] = "あいう";
$sdata[5] = "かきく";
$sdata[6] = "あいう";
$sdata[7] = "かきく";
$sdata[8] = "かきく";
$sdata[9] = "END番兵"; // 番兵
$sdata[10] = "これはなし";

#ndata[0] = 100;
#ndata[1] = 20;
#ndata[2] = 0;
#ndata[3] = 1000;
#ndata[4] = 99;
#ndata[5] = -99999; // 番兵変わり


js {

// 秀丸マクロのとある配列の要素を取得する(JavaScriptで仮実装したもの)
function getArrayVarItem(arrayvar_name, index) {
    let typesimbol = arrayvar_name[0];
    evalMacro(typesimbol + "_GETARRVARITEM_ = " + arrayvar_name + "[" + inde
x + "]");
    return getVar(typesimbol + "_GETARRVARITEM_");
}

// 秀丸マクロのとある配列の要素へ代入する(JavaScriptで仮実装したもの)
function setArrayVarItem(arrayvar_name, index, value) {
    let typesimbol = arrayvar_name[0];
    evalMacro(arrayvar_name + "[" + index + "] = " + JSON.stringify(value));
}

debuginfo(2);

//----------------------------------------------
    console.log("マクロ→JSの配列構築パターン1");
    let sarr1 = Array.from({length:9}, (_,i)=>getArrayVarItem("$sdata", i));
 // 長さ「9」を自分でマニュアルで管理。マクロ部分との追従を忘れる怖さは残る
が...
    console.log(JSON.stringify(sarr1));

    let narr1 = Array.from({length:5}, (_,i)=>getArrayVarItem("#ndata", i));
 // 長さ「5」を自分でマニュアルで管理。マクロ部分との追従を忘れる怖さは残る
が...
    console.log(JSON.stringify(narr1));


//----------------------------------------------
    console.log("マクロ→JSの配列構築パターン2"); // 番兵などを使うならこれか。
    let sarr2 = [];
 for (let i = 0; i < 100; i++) { // 十分すぎる長さ(万が一番兵が抜けている場
合にそなえて、無限ループにはしない)
        let item = getArrayVarItem("$sdata", i);
        if (item == "END番兵") { break; }
        sarr2.push(item);
 }
    console.log(JSON.stringify(sarr2));

    let narr2 = [];
 for (let i = 0; i < 100; i++) { // 十分すぎる長さ(万が一番兵が抜けている場
合にそなえて、無限ループにはしない)
        let item = getArrayVarItem("#ndata", i);
        if (item == -99999) { break; }
        narr2.push(item);
 }
    console.log(JSON.stringify(narr2));


//----------------------------------------------
    console.log("JS→マクロへの配列代入");
    setArrayVarItem("$sdata", 100, "たちづ");

    setArrayVarItem("#ndata", 50, 200);

}

message($sdata[100]);

message(str(#ndata[50]));


// ---------------------------------------------

ECMAScript側が現代では結構強烈なので、粒が小さい橋渡しを用意しておくだけでも


let arr = Array.from({length:5}, (_,i)=>getArrayVarItem("#ndata", i))

みたいに、結構グっと拾い上げることができるっていうかなんていうか。
初心者でも普通にforで書いて配列へと仕立てるのは難しくないでしょうし。

[ ]
RE:10463 秀丸マクロの配列のJavascriptとNo.10464
ラフ さん 24/09/16 18:47
 
いろいろ考えて頂きありがとうございます。
拙作のMacroMenu.macの高速化(と言ってもメニューファイルの読み込み関連だけです
が)Trimを実現するのに、VBScript.RegExpを使用てるのが問題かなと最初考えていて、
Jsなら文字列のreplaceで正規表現使えるじゃんってことでやってみたらさらに遅く
なった(笑)
で根本から考えていろいろテストプロで計測して、
まず、ループ中にcall文でtrim処理のサブルーチン呼び出しがまず遅い。その場に展
開すると一気に速くなることが分かった。
で逆にJSモードに切り替えるオーバーヘッドがすごく大きいという事も判明してJS
モード断念。
最後にHmJreとRegExpの性能比較すると、HmJreの方が少し速いので最終的にはHmJre
に置き換えようかなと思っています。

ちなみに私のwindows8時代に組み立てたちょい遅いPC(^^;でのテストプロでの結果は
HmJreは100000回のループ処理に3859ミリ秒かかりました
RegExpは100000回のループ処理に4422ミリ秒かかりました
JSは1000回のループ処理に1937ミリ秒かかりました
js{}の中身だけは空っぽです。残り二つはちゃんとtrim処理してます。

ということで、ループがそこそこの回数回るなら、中でcall文は極力少なく、jsの切
り替えはループ外での処理のみにするという結論に達しました。

以上です。

[ ]
RE:10464 秀丸マクロの配列のJavascriptとNo.10465
こみやんま さん 24/09/17 01:45
 
>js{}の中身だけは空っぽです。残り二つはちゃんとtrim処理してます。

データ自体をjsonかjs内で定義して、そのままjs内でtrimした場合はどのぐらいにな
るんですか?

100000回だとして

[ ]
RE:10465 秀丸マクロの配列のJavascriptとNo.10467
ラフ さん 24/09/17 17:31
 
>>js{}の中身だけは空っぽです。残り二つはちゃんとtrim処理してます。
> ......
>100000回だとして
100000回は200秒くらいかかるので1000回で(値を100倍してください)。
JS(切り替えのみ)は1000回のループ処理に1984ミリ秒かかりました
JS+trimは1000回のループ処理に2125ミリ秒かかりました
JS+trim+getVar/setVar は1000回のループ処理に2094ミリ秒かかりました
js内の処理は速いので余り問題ないかなと。他ソフトも操作はしていないけど動いて
るから今回は3番目の方が2番目より速くなってますが。

ちなみに該当部分はこんな感じ
while(#i < #maxcount) {
 $src ="  a b c d e  ";
 if(#mode == 0) {
  $s = dllfuncstr(#objJre, "ReplaceRegular", "^\\s+(.*?)\\s+$", $src, 0, "\\
1", 1);
 } else if(#mode == 1) {
  setpropnum #objReg, "global", true;
  setpropstr #objReg, "pattern", "^\\s+|\\s+$";
  $s = member(#objReg, "replace", $src, "");
 } else if(#mode == 2) {
  js {
  }
 } else if(#mode == 3) {
  js {
   var ret = "  a b c d e  ";
   ret = ret.replace(/^\s+|\s+$/g, "");
  }
 } else { // #mode=4
  js {
   var ret = hidemaru.getVar("$src");
   ret = ret.replace(/^\s+|\s+$/g, "");
   hidemaru.setVar("$s", ret);
  }
 }
 #i = #i + 1;
}

[ ]