重複する行の名前を変更したい。No.10336
nobu1 さん 24/05/14 23:52
 
重複する行を削除するマクロはありますが、
重複する行を削除せずに、名前を変更するようなマクロはないでしょうか。

例えば、

りんご
りんご
みかん
みかん
ぶどう
ぶどう



りんご
りんご 2番
みかん
みかん 2番
ぶどう
ぶどう 2番

のように、重複する行に言葉を追加するような形にして、全体的に重複がなくなるよ
うにするマクロを探しています。
案を頂ければと思います。

[ ]
RE:10336 重複する行の名前を変更したい。No.10337
こみやんま さん 24/05/15 05:47
 
うーむ、まぁ
- ChatGPTなりで詳しく正しく内容を聞ける、書き換えられる
- 数十万行とかあっても数秒で処理が終わる

という点から以下みたいな処理が妥当ですかねぇ。
(目的を達成するだけならもっと短くはできますが、圧縮すればするほど応用が利か
なかったり、ChatGPTなGeminiなりCopilotなりで問い合わせが効かなくなるので)



----- test.mac -------

jsmode "WebView2";
js {
    // 対象となるワード(という行内容)と出現回数を引数として、どのようなテ
キストを返すのか。
    function customFunc(text, count) {

        // はじめての登場なら
        if (count == 1) {
            // そのまま返す
            return text;

        // 重複以降は
        } else {
            // 登場した回数を添える。
            return `${text} ${count}番`;
        }
    }

    // 通常の「範囲選択」のテキスト内容が対象。範囲選択していない場合、「テ
キスト全体」を対象とする
    function getTargetText() {
        return hidemaru.getSelectedText() || hidemaru.getTotalText();
    }

    // 警告用の関数。
    function outputAlert(e) {
        // エラーがあればアウトプット枠へ
        let dll = loaddll( "HmOutputPane.dll");
        dll.dllfunc.Output(hidemaru.getCurrentWindowHandle(), e + "\r\n");
    }

    try {
        let targetText = getTargetText();
        if (!targetText) {
            throw "対象のテキストが無効です";
        }

        // ワード内容と出現回数のハッシュ
        let countHash = {};

        // 各行内容を抽出する。
        let newText = targetText.replace( /^(.+?)\n?$/gm, (match, m1) => {
           if (m1.length == 0) {
               // 中身がなにもない行はそのまま返す。
               return match;
           }

           // 中身がある行は、該当のワードをキーにしてカウントと取る。出現す
る度に足してゆく。
           countHash[m1] = (countHash[m1] || 0) + 1;

           // どのような文字列にするかはカスタム関数で弄れるようにしておく
           return customFunc(m1, countHash[m1]);
        } );

        // 元々のテキストと新たなテキストに変更があれば、エディタ上での差し
替え行為が必要となる。
        let mustReplace = targetText != newText;

        // 修正が必要なようだ
        if (mustReplace) {
            begingroupundo();
            // 範囲選択でないならば、テキスト全体が対象なので全選択
            if ( !selecting() ) { selectall(); }
            // 新たなテキストへ
            insert(newText);
            endgroupundo();
        }
        else {
            throw "重複はありません";
        }
    }

    // エラーや警告の類が出たらここ
    catch(e) {
        outputAlert(e);
    }

}


[ ]
RE:10337 重複する行の名前を変更したい。No.10338
こみやんま さん 24/05/15 06:54
 
愚直にforを使って繰り返しで処理を記述してた方が理解がしやすい、
といったことであれば、
以下のように変更してみても良いかと思います。

--- test.mac ---

jsmode "WebView2";
js {
    // 対象となるワード(という行内容)と出現回数を引数として、どのようなテ
キストを返すのか。
    function customFunc(text, count) {

        // はじめての登場なら
        if (count == 1) {
            // そのまま返す
            return text;

        // 重複以降は
        } else {
            // 登場した回数を添える。
            return `${text} ${count}番`;
        }
    }

    // 通常の「範囲選択」のテキスト内容が対象。範囲選択していない場合、「テ
キスト全体」を対象とする
    function getTargetText() {
        return hidemaru.getSelectedText() || hidemaru.getTotalText();
    }

    // 警告用の関数。
    function outputAlert(e) {
        // エラーがあればアウトプット枠へ
        let dll = loaddll( "HmOutputPane.dll");
        dll.dllfunc.Output(hidemaru.getCurrentWindowHandle(), e + "\r\n");
    }

    try {
        let targetText = getTargetText();
        if (!targetText) {
            throw "対象のテキストが無効です";
        }

        // ワード内容と出現回数のハッシュ
        let countHash = {};

        // 各行を改行を除去した状態で配列として格納
        let textArray = targetText.split(/\r?\n/);

        // 各行を処理していく
        for (let i=0; i<targetText.length; i++) {
            // 対象の行のテキスト
            let text = textArray[i];
            // 有効文字がないなら次へ
            if (!text) { continue; }

            // そのキーが初ならまずカウンタとして0で数値として扱えるようにする
            if (countHash[text] == null) { countHash[text] = 0; }
            // 1つカウントアップ
            countHash[text]++;
            // カスタム関数を使って、加工する
            textArray[i] = customFunc(text, countHash[text]);
        }

        let newText = "";
        if (targetText.includes("\r\n")) {
            // \r\n が改行だったなら、\r\nでくっつける。
            newText = textArray.join("\r\n");
        } else {
            // \nが改行だったなら\nでくっつける。
            newText = textArray.join("\n");
        }

        // 元々のテキストと新たなテキストに変更があれば、エディタ上での差し
替え行為が必要となる。
        let mustReplace = targetText != newText;

        // 修正が必要なようだ
        if (mustReplace) {
            begingroupundo();
            // 範囲選択でないならば、テキスト全体が対象なので全選択
            if ( !selecting() ) { selectall(); }
            // 新たなテキストへ
            insert(newText);
            endgroupundo();
        }
        else {
            throw "重複はありません";
        }
    }

    // エラーや警告の類が出たらここ
    catch(e) {
        outputAlert(e);
    }

}


[ ]
RE:10338 重複する行の名前を変更したい。No.10339
nobu1 さん 24/05/15 16:03
 
初歩的な質問ですいません。
秀丸マクロに書いて実行したところ、
一行目に「文法エラーです。」が出ます。

WebView2 ランタイムが不足しているのかと思い、ダウンロードして実行してみまし
たが、すでにEdgeにインストールされています。と出ます。秀丸は8.99です。
すいませんが、教えてもらえませんか。

[ ]
RE:10339 重複する行の名前を変更したい。No.10340
こみやんま さん 24/05/15 21:23
 
>WebView2 ランタイムが不足しているのかと思い、ダウンロードして実行してみまし
>たが、すでにEdgeにインストールされています。と出ます。秀丸は8.99です。


秀丸のバージョンが不足しています。
最低でも「jsmode/JavaScript」のマクロが利用可能な「9.19」は必要かと。

普通に最新版の秀丸導入をすれば動作するかと思います。

(特にinsert関数がネイティブなバージョンである方が望ましいので)


[ ]
RE:10336 重複する行の名前を変更したい。No.10341
igus さん 24/05/15 22:48
 
rubyを使って良ければもっと簡単に書けて早くなるんだけど
とりあえずは秀丸縛りで

//重複する行の名前変更.mac

if(!selecting){selectall}else{selectline 1;}
begingroupundo;copy2;delete;
openfile "";paste;saveas "tmp.txt";escape;gofiletop;
beginclipboardread;
#i=0;#j=0;#k=0;
while(1){
  $a[#i]=getclipboard();
  if($a[#i]=="")break;
  #i=#i+1;
}
while(#j<#i){
  escape;moveto 0,0;beginsel;moveto 0,#j+1;sleep 300;
  replaceallfast "^"+$a[#j],$a[#j],regular,inselect2;
  #b[#j]=result;
  #j=#j+1;
}
#j=0;
while(#j<#i){
  if(#b[#j]>1){moveto 0,#j;golineend;insert " "+str(#b[#j])+"番目";}
  #j=#j+1;
}
save;selectall;copy;
setactivehidemaru 1;
paste;endgroupundo;

[ ]
RE:10341 重複する行の名前を変更したい。No.10342
igus さん 24/05/15 22:51
 
動作が遅いと思ったら確認用にsleep 300;とか入れてて消すのを忘れてました。orz。
sleep 300;は消しといて下さい。

[ ]
RE:10342 重複する行の名前を変更したい。No.10343
こみやんま さん 24/05/15 23:11
 
上のマクロはテキストが5万行だと何分かかるの...

[ ]
RE:10342 ありがとうございますNo.10344
nobu1 さん 24/05/16 02:31
 
できました!
すごいです。秀丸の応用の幅広さは群を抜いてますね。

[ ]
RE:10340 ありがとうございますNo.10345
nobu1 さん 24/05/16 02:45
 
今回は別の方ので成功しましたので動作までいきませんでしたが、ありがとうござい
ます!いろいろなやり方があるということで参考にさせて頂きます。

秀丸9以上だと、複数ファイルにマクロ実行というマクロと、andGrepの旧版(新版
は除外ができない)の2つのファイルが動かないんです。これらがすごい役立つので
仕方ないんです。
ありがとうございました。

[ ]
RE:10342 エラーが発生しています。No.10346
nobu1 さん 24/05/16 03:58
 
平均25文字前後のものを、1300行あたりでエラーになり、止まってしまいます。
エラー内容は、
「秀丸メールのプロセスで保護違反が発生しました。秀丸メールは異常終了しま
す。」です。「dump.txtでエラーを出力しました。インストールしたフォルダかドキ
ュメントフォルダにあります。」と出るので、どちらもフォルダとその周辺を探して
みましたが、このファイルはありませんでした。

1300行付近で怪しい動きで止まるので、その付近の前後の300行を省いてみま
したが、この付近の行で止まります。どうやら文字数で引っ掛かっているようです。
先ほどの成功時と同じように1000行でやってみたら、うまくいきました。行数が
3万行近くあるので、行数の制限を解除したいのですが、良い方法はありますでしょ
うか?
秀丸8.99で、32bitバージョンで実行しています。

[ ]
RE:10345 ありがとうございますNo.10347
こみやんま さん 24/05/16 04:13
 
>秀丸9以上だと、複数ファイルにマクロ実行というマクロと、andGrepの旧版(新版
>は除外ができない)の2つのファイルが動かないんです。これらがすごい役立つの
>で仕方ないんです。
>ありがとうございました。

うーむ、なるほど、
それらの「2つのマクロ」は試していませんが、8⇒9へと上がった際に、
「カレントフォルダ」が自動的には移動しなくなっているので、
マクロの性質を推測するに、それが濃厚ですかねぇ。



秀丸のヘルプに
//==================================================
現在開いているファイルに対するマクロの操作がバージョンアップしたらうまくいか
なくなった。
 [その他]→[動作環境]→[トラブル対策]→[その他のトラブル対策]の下の方の「カ
レントフォルダ移動」の設定が「自動」の場合、V9.00から移動しない相当に変更に
なった影響の可能性があります。
 ここを「移動する(従来通り)」にすると従来通りになります。
//==================================================
みたいな項目があるかと思いますが(ググってもいいです)

こちらは試されましたか?

[ ]
RE:10345 「秀丸8.x維持」ならhmJSが良いNo.10348
こみやんま さん 24/05/16 06:05
 
「秀丸エディタ 8.9x を維持しなければ」、ならないのであれば、

hmJS.dllというファイルを1つ「秀丸エディタ本来exeと同じフォルダ」に導入でき
るのであれば、
以下のマクロでも動作します。
(hmV8が導入できるのであれば、先に投稿していたものがほとんどそのまま動作しま
すが、外部dllを導入するならファイル数が1つとかの方が気楽でしょう。)

hmJS.dll
└ https://xn--pckzexbx21r8q9b.net/?page=nobu_tool_hm_javascript


これでも 3万行程度なら、1〜3秒程度だと思います(マシンパワーによる)

----- test.mac -----

#JS = loaddll( hidemarudir + @"\hmJS.dll" );
if ( !#JS ) { message "hmJS.dllが読み込めない"; }
 
#r = dllfuncw( #JS, "DoString", R"JS(

function customFunc(text, count) {
    // はじめての登場なら
    if (count == 1) {
        // そのまま返す
        return text;
        // 重複以降は
    }
    else {
        // 登場した回数を添える。
        return text + " " + count + "番";
    }
}
// 通常の「範囲選択」のテキスト内容が対象。範囲選択していない場合、「テキス
ト全体」を対象とする
function getTargetText() {
    return hidemaru.getSelectedText() || hidemaru.getTotalText();
}
// 警告用の関数。
function outputAlert(e) {
    // エラーがあればアウトプット枠へ
    hm.OutputPane.Output(e + "\r\n");
}
try {
    var targetText = getTargetText();
    if (!targetText) {
        throw "対象のテキストが無効です";
    }
    // ワード内容と出現回数のハッシュ
    var countHash = {};
    // 各行を改行を除去した状態で配列として格納
    var textArray = targetText.split("\r\n");
    // 各行を処理していく
    for (var i = 0; i < targetText.length; i++) {
        // 対象の行のテキスト
        var text = textArray[i];
        // 有効文字がないなら次へ
        if (!text) {
            continue;
        }
        if (countHash[text]) {
            // 1つカウントアップ
            countHash[text]++;
        } else {
            countHash[text] = 1;
        }
        // カスタム関数を使って、加工する
        textArray[i] = customFunc(text, countHash[text]);
    }

    newText = ""; // 後でマクロ側から取得するため、グローバル変数にしておく。

    newText = textArray.join("\r\n");

    // 元々のテキストと新たなテキストに変更があれば、エディタ上での差し替え
行為が必要となる。
    var mustReplace = targetText != newText;

    // 秀丸マクロに伝達。
    setVar("#mustReplace", mustReplace);

    // 修正が必要なようだ
    if (!mustReplace) {
        outputAlert("重複はありません");
    } else {
        outputAlert("重複を発見しました");
    }
}
// エラーや警告の類が出たらここ
catch (e) {
    outputAlert(e);
}

)JS"
);

// 修正が必要なようだ
if (#mustReplace) {

    begingroupundo;
    if (!selecting) {
        selectall;
    }

    // 30000行あるならば、秀丸マクロの変数で受け取るのは危険。
    // メモリ消費を避けるため、マクロの一時変数で受け取らず、JS変数内容をか
らそのままエディタペインへと挿入
    insert dllfuncstrw(#JS, "GetStrVar", "newText");
    endgroupundo;
}

freedll( #JS );

[ ]
RE:10346 エラーが発生しています。No.10349
igus さん 24/05/16 11:28
 

試しに5万行くらいので試したところいつまで経っても終わらず
rubyで書き直したのを試しても処理の仕方が悪いのかかなり時間がかかったんですが
こみやんまさんのマクロだと瞬殺で今回の場合は素直に秀丸のバージョンアップをして
こみやんまさんのマクロを試されることを強くお勧めします。

旧版のマクロが動かないのはそれはそれでマクロ会議室のネタになるのでは:-)

[ ]
RE:10348 ありがとうございます。No.10350
nobu1 さん 24/05/17 06:40
 
このファイルを入れるだけで、1秒で成功しました。
ありがとうございました。

上記2つの物が使えない件で、さらに追加すると新しいgrepマクロもor検索が使えな
い症状がありました。これは、本体の標準のマクロで対応可能でした。
さらに2つの症状があり、9.2以降の症状でマクロの新規作成と編集ができない状
態となりました。保存ボタンが潰れていて保存できませんでした。権限を無理やりい
じったところ、「上書き禁止のファイルに書き込もうとしたか、またはアクセス権限
がありません。」のような表示があった記憶があります。
これらの理由から8.99はすべて正常に動き、それ以降に行く理由がなかったため
落ち着いています。

マクロ3点については作者に要望を出し(返事はなし)、マクロのバグに関しては気
づきやすいバグですので、私の環境依存の原因かなと思って、現在のバージョンの使
用に至っています。
もし9に上げる機会があったら試してみたいと思います。この度は、ありがとうござ
いました。


[ ]
RE:10350 andGrep不具合についてNo.10351
igus さん 24/05/17 09:05
 
andGrepダウンロードしてみました
私の秀丸エディタのバージョンはVer9.32Beta4
起動時のエラーメッセージについては以下の部分を変更すれば直るみたい

andGrep.mac
463行目:  dllfunc("SETCTRLNOTIFY", "", $id_FullPath) && //末尾に&&追加
476行目:  dllfunc("SETCTRLNOTIFY", "", $id_Report) &&   //末尾に&&追加

まだ使い方すらよく分かってない状態ですが不具合点を再現可能な手順で教えてもら
えれば、もしかするとなんとかできるかもしれません。

[ ]
RE:10350 ありがとうございます。No.10352
秀丸担当 さん 24/05/17 11:16
 

マクロが保存できないというのは、おそらくですが、Program Files配下への書き込
みかなと思います。
主な変更と注意点は以下のページにあります。
https://hide.maruo.co.jp/software/hidemarunew/v900_1.html

Program Files配下については、V8.xx以下からの引き継ぐ場合は従来通りになります。
新規インストール時に変わることになります。

保存ボタンが潰れるというのはおそらくバグだと思います。
ただ再現できず、どういう状況か不明です。
操作手順など教えていただけると助かります。
差支えなければ手順と共に[その他]→[設定内容の保存/復元...]でファイルに保存し
たものを"taki@maruo.co.jp"まで送っていただけると再現させやすいので調査します。

[ ]