複数行の検索で (?\\1) が使えないNo.02419
IKKI さん 09/05/03 20:22
 
こんにちは。IKKI です。

正規表現検索で、ヒットした扱いにするタグの指定 (?\\1) があるとき、
当該部分がヒットした範囲の 2 行目以降にあると、検索が失敗するようです。
また、失敗したとき前回の結果がクリアされずに残っているようです。

●テストマクロ
searchdown "(?\\1)(hoge)\\nfuga", regular;
message gettext(foundtopx, foundtopy, foundendx, foundendy, 1);
searchdown "(?\\1)hoge\\n(fuga)", regular;
message gettext(foundtopx, foundtopy, foundendx, foundendy, 1);

●テストデータ
hoge
fuga
hoge
fuga

●期待する結果
1回目: 「hoge」
2回目: 「fuga」

●実際の結果
1回目: 「hoge」
2回目: 「hoge」

ご確認のほどよろしくお願いいたします。

秀丸エディタ v7.11 + HmJre v2.00
Vista SP1

[ ]
RE:02419 複数行の検索で (?\\1) が使えなNo.02420
Iranoan さん 09/05/03 23:51
 
 IKKI さん今日は、Iranoan です。
> 正規表現検索で、ヒットした扱いにするタグの指定 (?\\1) があるとき、
> 当該部分がヒットした範囲の 2 行目以降にあると、検索が失敗するようです。
 確かこれは仕様です。
http://hidemaruo.dip.jp:81/turukame/turukame_1/x0801373.html#1374

> HmJre.dllがヒットした位置を返す時に、もしその位置が改行文字よりも後ろで
> ある場合には、秀丸エディタはヒットした扱いにしないです。
と秀丸エディタ側の処理とのことなので、ひょっとすると改善されるかもしれ
ませんが。

[ ]
RE:02420 複数行の検索で (?\\1) が使えなNo.02421
IKKI さん 09/05/04 11:22
 
こんにちは。IKKI です。

>  確かこれは仕様です。
> →http://hidemaruo.dip.jp:81/turukame/turukame_1/x0801373.html#1374

ご教示ありがとうございます。

秀丸担当さん:
秀丸エディタ側はどういう理由ではじいているのでしょうか?
また、ヒットした扱いにできる見込みはあるでしょうか?

[ ]
RE:02421 複数行の検索で (?\\1) が使えなNo.02422
秀まるお さん 09/05/04 23:26
 
 秀丸担当が休みなので僕がとりあえずお返事しますけども…。

 「\n」を含む検索をした場合、例えば\nを1つだけ含む文字列を検索する場合、
秀丸エディタ側は、HmJre.dllに、2行を1セットで渡す形になります。

 例えば

 aaaa
 bbbb
 cccc
 [EOF]

 という行がある場合、

  aaaa\nbbbb\n
  bbbb\ncccc\n
  cccc\n

 という形で文字列を順に渡して検索させます。

 ここで仮に、HmJre.dll側でヒットした文字列が、「\n」よりも後ろである場
合には、それはヒットした扱いにはしないです。なぜかというと例えば「aaaa\
nbbbb\n」で「bbbb」の所にヒットするということは、次に「bbbb\ncccc\n」を
検索させた時には「bbbb」の所に必ずヒットするはずだからです。

 そういう風にしてやらないと、「下候補」のコマンドを実行した時に同じ文字
列に2回ヒットする可能性があります。とにかく1つの文字列には1回しかヒッ
トさせないということが必要なので、\n以降にヒットした物はヒットしなかった
扱いにしています。

> また、ヒットした扱いにできる見込みはあるでしょうか?

 いろいろ経験的に作り上げた処理なので無理で今さらいじるのは難しいんじゃ
ないかと思います。

 そもそもこの「(?\1)」みたいな正規表現自体が僕が独自に追加してしまった
物なのですが、このような矛盾が起きることはまったく想定してませんでした。
今さらながら、こんなの追加するんじゃなかったなぁと思います。

[ ]
RE:02422 複数行の検索で (?\\1) が使えなNo.02423
Iranoan さん 09/05/05 00:05
 
 秀まるおさん今日は、Iranoan です。
>  「\n」を含む検索をした場合、例えば\nを1つだけ含む文字列を検索する場合、
> 秀丸エディタ側は、HmJre.dllに、2行を1セットで渡す形になります。
 仕様は仕様として解りましたので、改善して欲しいというわけではなく、次
のように考えるユーザもいるということで。

>  そういう風にしてやらないと、「下候補」のコマンドを実行した時に同じ文字
> 列に2回ヒットする可能性があります。とにかく1つの文字列には1回しかヒッ
> トさせないということが必要なので、\n以降にヒットした物はヒットしなかった
> 扱いにしています。
 「.+」の検索などは、今でも複数回ヒットします (ヒットの終端が変化しな
い)。そうすると、「\n」を使うのは正規表現に限られていますので、複数回
のヒットを許しても良い気もします。(マクロの互換性を確保する必要が有る
ので、今更変更できないでしょうが)

>  そもそもこの「(?\1)」みたいな正規表現自体が僕が独自に追加してしまった
> 物なのですが、このような矛盾が起きることはまったく想定してませんでした。
> 今さらながら、こんなの追加するんじゃなかったなぁと思います。
 前方/後方の一致/不一致はあわせて使えず、個別に書式です。それに対して
(?\1) は別々に覚える必要も無いので、非常に嬉しい機能として使わせて頂い
ています。

[ ]
RE:02422 複数行の検索で (?\\1) が使えなNo.02424
IKKI さん 09/05/06 18:49
 
こんにちは。IKKI です。

報告した点については、現状では仕様ということで了解しました。
お休みのところご返信いただきありがとうございました。


ですが、「1つの文字列には1回しかヒットさせない」ために、どうして
「\n以降にヒットした物はヒットしなかった扱いに」しなければならないのかは
よくわかりませんでした。

 アイウエオ
 カキクケコ
 サシスセソ
 [EOF]

という文書に対し

 (?\1)[ア-ン\n]+(キクケ)

というパターンで下検索したら「キクケ」が 1 度だけヒットしてほしいんですよね。
現状では、秀丸エディタが HmJre.dll に渡す文字列は

 1回目: アイウエオ\nカキクケコ\n 《ヒットするが、しなかった扱いにする》
 2回目: カキクケコ\nサシスセソ\n 《ヒットする》

となっています。しかし、もっと素直に

 1回目: アイウエオ\nカキクケコ\n 《ヒットする》
 2回目: クケコ\nサシスセソ\n   《ヒットしない》

とすれば問題はなくなるように思います。
後者は現状の (\n を含まないパターンの) 下検索の動作と矛盾しません。
前者のように複雑な処理をする理由が何かあったでしょうか…。


---- 以下、元の話題から離れます ----

そもそも「(パターン中の \n の数 + 1) 行だけを検索対象とする」という仕様は
わかりにくく、初心者だけでなく他のエディタから乗り換えたユーザさんも
戸惑うポイントのようです。また、今回の話のような矛盾の原因にもなります。

>  いろいろ経験的に作り上げた処理なので無理で今さらいじるのは難しいんじゃ
> ないかと思います。

まあ、仰ることはよくわかるのですが…
複数行検索の不便さは秀丸の弱点のひとつでもあるので、将来的にこれを克服し
\n+ のようなパターンにも対応できるよう、もう少し突っ込んで検討する価値は
あるんじゃないかと思います。

>  そもそもこの「(?\1)」みたいな正規表現自体が僕が独自に追加してしまった
> 物なのですが、このような矛盾が起きることはまったく想定してませんでした。
> 今さらながら、こんなの追加するんじゃなかったなぁと思います。

いや、今回の話は秀丸エディタ側が以前から抱えていた問題が露呈しただけで、
HmJre 側の機能としては何も問題ないと思いますよ。(^^;

[ ]
RE:02424 複数行の検索で (?\\1) が使えなNo.02426
秀丸担当 さん 09/05/07 10:29
 

>ですが、「1つの文字列には1回しかヒットさせない」ために、どうして
>「\n以降にヒットした物はヒットしなかった扱いに」しなければならないのかは
>よくわかりませんでした。

>---- 以下、元の話題から離れます ----
>複数行検索の不便さは秀丸の弱点のひとつでもあるので、将来的にこれを克服し
>\n+ のようなパターンにも対応できるよう、もう少し突っ込んで検討する価値は
>あるんじゃないかと思います。


この2つの話題に共通することですが、正規表現DLLに文字列を渡すときは、一
度メモリ確保して行単位でメモリ上にコピーしたデータを渡しているということ
が大きな理由なのではないかと思います。

秀丸エディタは、開いたファイルをファイルの先頭から最後までを連続したメモ
リ上にベタなテキストとして持っているわけではなく、メモリ領域は連続してい
なかったり、\nが付いていなかったりします。

正規表現DLLに渡すときは、行単位で取り出して\nを付けて繋げてから渡してい
ます。


調べてみたら、この判断は、HmJre.dllによる(?\1)ができる前からありました。
例えば、検索文字列が「a\nb*」で、DLLに渡す文字列が2行分の場合、

xxxx
aaaa
bbbb
[EOF]


というテキストだと最初にDLLに渡す文字列は

xxxx\naaaa\n

になります。

そうすると、最初に「a\n」にマッチしてしまいます。
本当にマッチしなくてはいけないのは「a\nbbbb」なので、「a\n」だけにマッチ
してしまうとまずいので、渡した文字列の一行目の部分にしかマッチしないよう
にしないといけないようです。

あと、後者の話題も合わせると、「\n」の数の行数制限を取っ払うことができれ
ば理想なのですが、ファイルの先頭から最後まで連続したメモリ領域で\nが付い
た文字列を作っておかなくてはいけないということになると、現時点では難しい
ようです。

仮にできたとしたら、DLLにはとても大きなサイズの対象となる文字列が常に渡
ることになるので、もしかしたら検索対象が大きくなることで速度が遅くなると
いったような、別の問題も出てくるかもしれないです。

[ ]
RE:02426 複数行の検索で (?\\1) が使えなNo.02432
Iranoan さん 09/05/07 17:37
 
 秀丸担当さん今日は、Iranoan です。
 仕様を変更して欲しいわけではありませんが、説明が解らないので、質問さ
せていただきます。

 まず確認ですが、
> 例えば、検索文字列が「a\nb*」で、DLLに渡す文字列が2行分の場合、
>
> xxxx
> aaaa
> bbbb
> [EOF]
の場合、
(1) xxxx
    aaaa
(2) aaaa
    bbbb
の順で DLL にデータを渡すんですよね。
 そこで、なぜ (1) の時に、
> そうすると、最初に「a\n」にマッチしてしまいます。
となるのでしょう。検索文字列が「a\nb*」なら、この段階では、DLL に渡し
たデータの
aaaa
以降が空なのでマッチせず、(2) の段階で始めてマッチする気が...。

 元々 \n の数+1 行分データを渡し、内部でストリームとしてデータを持ち、
検索文字列をストリームとして扱えば、
> 渡した文字列の一行目の部分にしかマッチしないよう
> にしないといけない
という事も必要無い気がします。(←結局 IKKI さんの指摘と同じか)
 もちろんこんな単純なやり方だけでは、例とした検索文字列とは別の a\n*
とした時に 2 回ヒットするという弊害が生まれますが...。

[ ]
RE:02432 複数行の検索で (?\\1) が使えなNo.02433
秀丸担当 さん 09/05/07 18:07
 

>aaaa
>以降が空なのでマッチせず、(2) の段階で始めてマッチする気が...。

「a\nb*」の「b」は0文字でもいいので、「xxxx\naaaa\n」という文字列に対し
て検索すると最後の「a\n」にもマッチすると思います。

そうすると、そもそも2行目の「\n」は渡さなくていいんじゃないか、という話
にもなってきそうですが。
検索文字列に「\n」を含まず「[^a]」の場合は「\n」にマッチするので、\nが一
個も無くても\nを付ける必要があったり、など、1つの例だけでは収まらないこ
とがいろいろありそうです。
なんとかうまいことする方法もあるのかもしれませんが、現時点ではできないで
す。

[ ]
RE:02433 複数行の検索で (?\\1) が使えなNo.02434
Iranoan さん 09/05/07 21:26
 
 秀丸担当さん今日は、Iranoan です。
> 「a\nb*」の「b」は0文字でもいいので、「xxxx\naaaa\n」という文字列に対し
> て検索すると最後の「a\n」にもマッチすると思います。
 そうですね。? も含めて、0 個というのがネックになっているんですね。

[ ]
RE:02426 複数行の検索で (?\\1) が使えなNo.02435
IKKI さん 09/05/08 00:04
 
こんばんは。IKKI です。
丁寧にご返答いただきありがとうございました。

> 例えば、検索文字列が「a\nb*」で、DLLに渡す文字列が2行分の場合、
(略)
> そうすると、最初に「a\n」にマッチしてしまいます。

そうですね。私の考えが足りなかったようです。

> あと、後者の話題も合わせると、「\n」の数の行数制限を取っ払うことができれ
> ば理想なのですが、ファイルの先頭から最後まで連続したメモリ領域で\nが付い
> た文字列を作っておかなくてはいけないということになると、現時点では難しい
> ようです。

たしかに難しいかもしれません。私は Windows プログラミングに関しては
素人なので、何も具体的なアイディアは出せないのですが。

ファイルから Grep する場合は可能かな、とか…
\n で区切らないとすると固定長で何バイトかずつ区切って渡すことになって、
その区切りをまたいでヒットする場合はどうなる? とか……
うーん。

# Dana は固定長 (256 バイト?) で区切っているようです。
# 完全に任意の行数をヒットさせることができる「テキストエディタ」は
# ないのかもしれません。

秀丸で編集中のテキストをバイト列として扱うことが必要な場合は、
変換モジュールを介して外部のスクリプトに投げるのが正解
という気がしてきました。

どうもお手数をおかけいたしました。

[ ]