,区切りのデータ列の整形についてNo.10266
tack さん 23/12/14 23:23
 
いつもお世話になっております。
毎回のようにお伺いさせていただくのも恐縮ではありますが、上手くいかないのでご
助言をいただきたく思います。

例文にあるような内容を,区切りで各々の順番に対応させて組み変えるのが目的です。
例文の要素は必ず,区切りになっています。

【例文】
"articles":["【開始】","「そんなわけで、今年もパーティーを開催する予定だから
","そのつもりでよろしく」","今年もこの時期がやってきた。","理由もわからない、
謎のパーティー。","いったい何を祝ってるのかはいまだに不明だけど、","例年参加
している。","【暗転】","「パーティー用のドレスやスーツは、今年も貸し出しする
んですか?」","「ええ、数に限りがあるから早いもの順だけど」"],
"characters":[[show-bg][play-voice]["0"],["1"],["2"],["3"],["4"],["5"],["6"],
[play-voice]["7"],["8"],[play-voice]["9"]],

【求める結果】
"【開始】",[show-bg][play-voice]["0"]
"「そんなわけで、今年もパーティーを開催する予定だから",["1"]
"そのつもりでよろしく」",["2"]
"今年もこの時期がやってきた。",["3"]
"理由もわからない、謎のパーティー。",["4"]
"いったい何を祝ってるのかはいまだに不明だけど、",["5"]
"例年参加している。",["6"]
"【暗転】",[play-voice]["7"]
"「パーティー用のドレスやスーツは、今年も貸し出しするんですか?」",["8"]
"「ええ、数に限りがあるから早いもの順だけど」"[play-voice]["9"]

【現在の結果】
●DATA1
"articles":[
"【開始】",
「そんなわけで、今年もパーティーを開催する予定だから",
そのつもりでよろしく」",
今年もこの時期がやってきた。",
理由もわからない、謎のパーティー。",
いったい何を祝ってるのかはいまだに不明だけど、",
例年参加している。",
【暗転】",
「パーティー用のドレスやスーツは、今年も貸し出しするんですか?」",
「ええ、数に限りがあるから早いもの順だけど」",
"[show-bg][play-voice]["0"]"
"["1"]"
"["2"]"
"["3"]"
"["4"]"
"["5"]"
"["6"]"
"[play-voice]["7"]"
"["8"]"
"[play-voice]["9"]"


【マクロ】
setcompatiblemode 0x00020000;
loaddll "hmjre.dll"; // HmJre.dll のロード ※2
disabledraw;
begingroupundo;//一撃で元に戻すためにグループ化

//並べ替えマクロ
//--------------------------------------
gofiletop;
#i = 0;
while( 1 )
{
searchdown2 "\"articles\":\\[.+?\\]", regular;
if( !result ) break; // while() ループの終了
$art[#i] = gettext( foundtopx, foundtopy, foundendx, foundendy );
//message "Article Data: " + $art[#i];

searchdown2 "(?\\2)(\"characters\":\\[)(.+?\\])(\\],)", regular;
if( !result ) { message "\"characters\":が見つかりません"; goto END; }
$cha[#i] = gettext( foundtopx, foundtopy, foundendx, foundendy );
//message "Character Data: " + $cha[#i];
#i = #i + 1;
}


#data_cnt = #i; // テキストデータの総数を格納

gofileend;
#i = 0;
while( #i < #data_cnt )
{
//「,」を区切り文字としてデータを分割し配列に格納 ※3
#c1 = split( $c, $cha[#i], "," );

// 見出しを追加
$s = "\n●DATA" + str( #i + 1 ) + "\n";
//整形
$s = $s + "\"" + $art[#i] + "\",\n";
$s = dllfuncstr( "ReplaceRegular", "\\[", $s, 0, "\\[\n", 2 );
$s = dllfuncstr( "ReplaceRegular", ",\"", $s, 0, "\",\n", 2 );


#j = 0;
while( #j < #c1 )
{

// データの並び替え
$s = $s + "\"" + $c[#j] + "\"\n";
#j = #j + 1;
}

//「""」を「"」に置換
$s = dllfuncstr( "ReplaceRegular", "\"\"", $s, 0, "\"", 2 );
// データの書き込み
insert $s;

#i = #i + 1;
}

END:

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

endgroupundo;
endmacro;

[ ]
RE:10266 ,区切りのデータ列の整形についNo.10267
こみやんま さん 23/12/15 01:10
 
重要なのは テキスト面上や文字列内で正規表現ぐりぐりで勝負しようとするのでは
なく、
「いかに取り扱いやすいオブジェクト形式」にするか、です。

「取り扱いにくいデータ」→「プログラム的に取り扱える(操作しやすい)オブジェク
ト」→「そのオブジェクトを使って改めて別の文字列を構築」
という考え方を「徹底する」ように癖をつけておかないと、
こういったことを疎かにすると、10年やってもほとんど成長しないですよ。

こういう癖をつけておくようにすると「内容によって出来たり出来なかったり」とい
ったことはなくなり
「理論的に可能な加工は全て短時間で自信で実装出来る」という安定した結果をご自
身で得られるようになります。

他のエディタに移っても100%通用する、同じ考え方で済むようにもなります。


jsmode "WebView2";
js {



// テキストからarticlesを配列的に取得
function getArticles(text) {
    let matchesA = text.match(/"articles":\[(.+)\],$/m);
    if (matchesA) {
        let articles = matchesA[1].split(",");
        return articles;
    }
}

// テキストからcharactersを配列的に取得
function getCharacters(text) {
    let matchesA = text.match(/"characters":\[(.+)\],$/m);
    if (matchesA) {
        let characters = matchesA[1].split(",");
        return characters;
    }
}

function getFormatText(articles, characters, format) {
    if (articles.length == characters.length) {
        let length = articles.length;
        let output_text = "";
        for(let i=0; i<length; i++) {
            output_text += sprintf(format, articles[i], characters[i]);
        }
        return output_text;
    }
    throw "articlesとcharactersで要素の個数が異なります。";
}

// ここでまともにプログラム的に取り扱える配列にできるようにしておく(刹那的に
やるのではなく、このような考え方がとても重要)

function main() {

    try {
        let text = hidemaru.getSelectedText();
        if (!text) {
            throw "対象のテキストが空です。";
        }
        let articles = getArticles(text);
        if (!articles) {
            throw "articlesが正しく把握できません。";
        }

        let characters = getCharacters(text);
        if (!characters) {
            throw "charactersが正しく把握できません。";
        }

        let result_text = getFormatText(articles, characters, '%s,%s\r\n');

        begingroupundo();
        selectall();
        insert(result_text);
        endgroupundo();
    } catch(ex) {
        let o = loaddll( "HmOutputPane.dll");
        o.dllfunc.Output(hidemaru.getCurrentWindowHandle(),ex);
    }
}

main();



} // js



[ ]
RE:10267 ,区切りのデータ列の整形についNo.10268
tack さん 23/12/15 01:23
 
なるほど、まずはオブジェクトを共通の形に作り替えてそれを扱うイメージを持つ、
ですね。

今回の場合
    try {
        let text = hidemaru.getSelectedText();
        if (!text) {
            throw "対象のテキストが空です。";
        }
「対象のテキストが空です。」を返すのです。
返す結果の内容は正しい結果なのですが、今回のマクロではここで動作停止をしてい
まいますが必要な要素なのでしょうか?

[ ]
RE:10268 ,区切りのデータ列の整形についNo.10269
こみやんま さん 23/12/15 01:40
 
テキストを選択してなかったら、対象のテキストが空になる、ということです。

そこは選択にするのか、なんか変数に格納しておいて、それを対象にするのか、決め
ればよいかと。
(矩形選択は hidemaru.getSelectedText() の対象にはならないので、矩形選択を対
象にするのであれば、そのようにくめばよいでしょう。)

JSでのやりかたがよくわからない、という場合は、
例えば、「秀丸マクロの層」で

$TEXT = ***** (対象の文字列を格納);

jsの層で

let text = getVar("$TEXT");

(秀丸マクロの$TEXTの変数の内容をjs側に拾う)
などといったやりかたもあります。





あとは、もしも articles の文字列自体(セリフのなか)にも「,」が入ることがあ
るということであれば、以下のように少し工夫が必要でしょう。
(単純な , で分離というわけにはいかなくなるので、正しくなるであろうパーサーを
通す)

// テキストからarticlesを配列的に取得
function getArticles(text) {
    let matchesA = text.match(/"articles":(\[.+\]),$/m);
    if (matchesA) {
        // let articles = matchesA[1].split(",");
        let articles = JSON.parse(matchesA[1]);
        articles = articles.map(s=>JSON.stringify(s));
        return articles;
    }
}

[ ]
RE:10269 ,区切りのデータ列の整形についNo.10270
tack さん 23/12/15 02:31
 
理解が悪く申し訳ありません、お聞きさせていただきたいのですが
今回のこのマクロでは配列的に取得した文字列はアウトプット枠で見る、琴も含めプ
ログラム的に別の文字列を構築する部分を目標にしているのでしょうか?
(アウトプット枠を使ったことが無いので、よく理解できていないのもありますが)

テキストの選択とあり、$TEXT = ***** (対象の文字列を格納);
とされていますが今回の動作で言えば、配列的に取得した内容をこの部分でアウトプ
ットさせるために必要、となるのでしょうか?

articlesの文字列内に,は存在しないのでそちらは問題ありません。

[ ]