[ 新規に投稿する ]

マッチした部分だけを取り出したいNo.41438
weio32hg さん 24/10/30 20:10 [ コメントを投稿する ]
  秀丸で、現在開いているテキストファイルを
正規表現を使って検索し、マッチした部分だけを
取り出したいです。
grepですと行まるごと取り出しになってしまいます。

具体的には、
各行でマッチした部分を取り出したいです。複数マッチした場合は
最初にマッチした部分だけを取り出します。

できればマクロを使わず、grep機能か検索機能などで可能でしょうか?
マクロを使ったほうが、処理したいときに、より簡単な操作でできるの
であればマクロでも構いません。

よろしくお願いいたします。
[ ]
RE:41438 マッチした部分だけを取り出したいNo.41439
こみやんま さん 24/10/31 03:41 [ コメントを投稿する ]
  これって簡単なようでいて、実は少しややこしい話が入り込んでいるんですが、

■検索結果のうちのカレントヒットが「選択」になるようにしては? という話

実は秀丸の「検索ヒットに対する表示方法」に2系統あって、

・点滅表示型(多分黄色とか?)
・範囲選択型

みたいな2系統があります。

普段から検索ヒットしたもので、(複数あったとしてもカレントヒットしているもの)は
「選択されていた方が良い」ということであれば、

```
その他 → 動作環境 → 検索 のページの一番上のところに
「点滅表示」と「範囲選択」がありますので、「範囲選択」を選んでおけばよいです。
```

weio32hg さんの使い方ですと、こちらの方がよいのかもしれません。
(というか大半の人は実はこちらの方がよいかもしれないw)

ただし、配布のマクロの中には、この「範囲選択」にしていることを想定しておらず、
このオプションを選択していると上手く挙動しないものも、もしかするとあるかもしれません。
(選択されていることが想定できてないマクロ)


■ただ取得するだけならマクロかな?

$text = gettext( foundtopx, foundtopy, foundendx, foundendy, 1 );
message $text;



■複数のヒット全部を取得するようなことが、将来あれば

setcompatiblemode 0x00020100; // ユーザーが利用する普段の検索条件を保存、サーチは点滅表示前提

js {

debuginfo(2); // デバッグ表示のため

colormarkerallfound();

var info = getcolormarker({
    unit: "wcs",
    layer: findmarker(),
    items: [
        { line1: "*", col1: "*", line2: "*", col2: "*", },
    ]
});

deletecolormarkerall(findmarker());

if (info.items) {
    for (var i = 0; i < info.items.length; i++) {
        var item = info.items[i];
        var text = gettext_wcs(item.col1, item.line1, item.col2, item.line2, 1);
        console.log(text + "\r\n");
    }
}

} // js


[ ]
RE:41438 マッチした部分だけを取り出したいNo.41440
igus さん 24/10/31 08:14 [ コメントを投稿する ]
  //行ごとにマッチ部分を取り出すよ.mac

$s=input("正規表現入力","s[a-z]+");
selectall;copy;openfile "";paste;saveas "kekka.txt";
begingroupundo;disabledraw;#y=1;
while(#y<=linecount2){
  $a="";movetolineno 1,#y;selectline 1;
  searchdown $s,regular,inselect2;
  if(result){
    $a=gettext(foundtopx,foundtopy,foundendx,foundendy);}
  movetolineno 1,#y;beginsel;golineend2;delete;
  insert $a;#y=#y+1;
}
enabledraw;endgroupundo;save;endmacro;
[ ]
RE:41440 マッチした部分だけを取り出したいNo.41441
こみやんま さん 24/10/31 09:19 [ コメントを投稿する ]
  前回の質問と解答(そして採用されたもの)から考えて、
どうも我々は勘違いしているかもw

aaaが対象であれば、

検索画面で、

(?<!aaa.+)aaa

で、「各行の最初の1個目」に全てヒットします。
秀丸がバグってて強調カラーは後ろの方にも付くでしょうが、
これは秀丸の強調カラーが多分バグっています。


そして前回と同じように「すべて検索」→「複数選択」
で選択状態にできるので、取り出せます。

[ ]
RE:41441 担当さんへNo.41442
こみやんま さん 24/10/31 09:23 [ コメントを投稿する ]
  検索窓に

(?<!aaa.+)aaa


aaaにaaaabbb要素
にaaabbbaaa要素

で、検索強調が後ろのaaaにも点灯するのは多分バグだと思います。
(前置き否定とかバグ直してる時に、処理判定が抜け落ちた?)


「すべて検索」→「複数選択」では正しいものが選択されています。

[ ]
RE:41441 マッチした部分だけを取り出したいNo.41443
こみやんま さん 24/10/31 09:28 [ コメントを投稿する ]
  >(?<!aaa.+)aaa

より厳密には、

(?<!aaa.*)aaa

です。

「+」ではなく「*」

[ ]
RE:41443 マクロにするとしたらNo.41445
こみやんま さん 24/10/31 14:20 [ コメントを投稿する ]
  毎回「前方否定の正規表現」とか付けてやるのめんどくせぇとか思ったら、
次みたいなマクロしかないと思います。

マクロ前に検索しておいても良いですし、先にマクロを実行しても良いです。
検索結果のうち、「各行のうち一番初めにヒットしたものを全て」を選択状態とします。


hidemaruversion "9.25.99";

setcompatiblemode 0x00020000; // ユーザーが利用する普段の検索条件を保存し、マクロが終わったら復元する。

js {

// カラーマーカー検知可能
colormarkerallfound();

function getSearchFindColorMarker() {
    // 「1度検索」したら「すべての対象位置の特定は終わってる」ので何度もマクロ内で再検索する必要はない。
    // 検索結果の情報を取り出すだけでよく、「全ての対象位置」がわかる。
    var info = getcolormarker({
        unit: "wcs",
        layer: findmarker(),
        items: [
            { line1: "*", col1: "*", line2: "*", col2: "*", },
        ]
    });

    return info;
}

// 検索結果の強調カラーマーカーを取得してみる
var info = getSearchFindColorMarker();

// 有効な検索結果(強調マーカー)が無い状態でこのマクロが実行されてるならば、検索ダイアログを出す
if (!info.items) {
    // 選択テキストがあればそれを使う。検索オプションは、それまでの検索で使っていたものをそのまま使う。
    searchdialog(getselectedtext(), searchoption(), searchoption2());
    colormarkerallfound();

    info = getSearchFindColorMarker();
}

deletecolormarkerall(findmarker());

if (info.items) {

    // 修正版itemsの格納先
    var normalized_items = [];

    // 同じ行のもので2個目以降は取り出さないという特別な処理のため、フィルター処理をする
    var last_line = -1;

    for (var i = 0; i < info.items.length; i++) {
        // 順繰りに取り出し
        var item = info.items[i];

        // 前回と行が同じならスキップ
        if (last_line == item.line1) { continue; }

        // 最新行を更新
        last_line = item.line1;

        // 対象のアイテムを追加
        normalized_items.push(item);
    }

    // 「同じ行のもので2個目以降のヒットは削除」した状態の情報で上書き
    info.items = normalized_items;

    // その情報をもとに「対象の全て」を「選択状態」とする
    setselectionrange(info);
}


} // js
[ ]
RE:41442 担当さんへNo.41446
秀丸担当 さん 24/10/31 15:25 [ コメントを投稿する ]
  バグ情報ありがとうございます。
調べてみたところ、V8.33でHmJre.dllがv4になってから、そういう動作になっていました。
詳しくは、HmJre.dllのヘルプの前方一致/前方不一致のところにあって、パフォーマンス的な都合によってそういう制約となっていました。
検索ダイアログのヘルプの検索文字列の強調のところにも、HmJre.dllのヘルプに誘導するようなことを書いておこうと思います。
別の書き方では、以下のようにすると検索結果も強調も大丈夫そうでした。
^.*?(aaa)(?\1)
[ ]
RE:41438 マッチした部分だけを取り出したいNo.41451
weio32hg さん 24/11/01 21:43 [ コメントを投稿する ]
 
詳細な回答ありがとうございました。

検索機能で
すべて検索-範囲選択 → コピー
を試し、

正規表現の毎回入力が大変になってきた場合には
お教えいただいたマクロを試そうと思います。

テキスト処理は業務効率化に直結するので大変助かりました。
[ ]

[ 新規に投稿する ]