searchdown2でhmonig.dllの\G\x{000A}の異No.09774
fzok4234 さん 22/03/21 14:31
 
毎度お世話になっております。


さて、searchdown2 文で正規表現 DLL を hmonig.dll にして、カーソル位置の改行
文字にマッチさせることを
意図して照合開始位置のアンカーの \G を使用して \G\x{000A} を検索したところ、
カーソル位置から大きく
離れた位置の改行文字に強引にマッチしてしまう不具合がありました。


検証マクロは次の通りです。

debuginfo 2 ;
#defaultCompatibleMode = setcompatiblemode(
        0x00000003
    |   0x0000000C
    |   0x00000200
    |   0x00020000
    |   0x00080000
    |   0x00400000
    |   0x00800000
    |   0x04000000
    |   0x08000000
) ;
#defaultTopY = screentopy ; #defaultLeftX = screenleftx ; disabledraw ; disa
bleinvert ;
#defaultColumn = column ; #defaultLineNo = lineno ;

#lineCount = 6 ;
#lineIndex = 0 ;
while ( #lineIndex < #lineCount ) {
    #lineNo = #lineIndex + 1 ;
    // カーソルを行頭に置く。
    moveto2 0 , #lineNo ;
    // カーソルのすぐ右隣の改行文字を選択状態にする。
    // カーソルの右隣は改行文字でない場合は失敗するはずである。
    searchdown2 @"(?#hmonig)(?#maxlines:1)(?#fulllinematch)(?u)\G\x{000A}" ,
 casesense , regular ;
    call WriteResult #lineNo , result ;
   
    #lineIndex = #lineIndex + 1 ;
}

moveto2 #defaultColumn , #defaultLineNo ;
enableinvert ; enabledraw #defaultTopY , #defaultLeftX ;
setcompatiblemode #defaultCompatibleMode ;
endmacro ;

WriteDebug :
    debuginfo $$1 + "\U0000000A" ;
    return ;

WriteTitle :
    call WriteDebug @"[" + $$1 + @"]" ;
    return ;

WriteValue :
    call WriteDebug $$1 + @" = " + str( ##2 ) ;
    return ;

WriteResult :
    call WriteTitle str( ##1 ) ;
    call WriteValue @"Result" , ##2 ;
    call WriteValue @"BeginLineNo" , seltoplineno ;
    call WriteValue @"BeginColumn" , seltopcolumn ;
    call WriteValue @"EndLineNo" , selendlineno ;
    call WriteValue @"EndColumn" , selendcolumn ;
    call WriteDebug @"" ;
   
    return ;


このマクロを以下のような 1〜3 行目は文字があって 4〜6 行目は改行文字だけのフ
ァイル ( UTF-8 、LF 、BOM有り )

0001 aaaaaaaa
0002 aaaaaaaa
0003 aaaaaaaa
0004
0005
0006

で実行したところ、次のような出力となりました。

[1]
Result = 1
BeginLineNo = 4
BeginColumn = 0
EndLineNo = 5
EndColumn = 0

[2]
Result = 1
BeginLineNo = 4
BeginColumn = 0
EndLineNo = 5
EndColumn = 0

[3]
Result = 1
BeginLineNo = 4
BeginColumn = 0
EndLineNo = 5
EndColumn = 0

[4]
Result = 1
BeginLineNo = 4
BeginColumn = 0
EndLineNo = 5
EndColumn = 0

[5]
Result = 1
BeginLineNo = 5
BeginColumn = 0
EndLineNo = 6
EndColumn = 0

[6]
Result = 1
BeginLineNo = 6
BeginColumn = 0
EndLineNo = 7
EndColumn = 0


結果は、カーソルが改行文字だけの行の行頭にある場合は searchdown2 は成功して
改行文字が選択されるという
正しい結果となりました。しかし、カーソルが任意文字を含む行の行頭にある場合は、
本来ならば searchdown2 が
失敗していなければならないのが、なぜか成功扱いになり、しかもカーソルから離れ
た位置にあるはずの行頭の
改行文字を選択してしまっている状態となっております。

このため、カーソル位置を表すアンカー \G を使って、カーソル位置の文字列が任意
の正規表現にマッチするかどうかを
searchdown2 を使って調べる際に、その正規表現が改行文字にマッチする場合に正確
な判定ができなくなってしまって
います。


環境は、

秀丸エディタ : 9.12 Float x64
hmonig.dll : 0.8.7.0
HmJreSelect.dll : 0.10

です。



[ ]
RE:09774 searchdown2でhmonig.dllの\G\x{No.09775
h-tom さん 22/03/21 16:44
 
h-tom です。

>結果は、カーソルが改行文字だけの行の行頭にある場合は searchdown2 は成功して
>改行文字が選択されるという
>正しい結果となりました。しかし、カーソルが任意文字を含む行の行頭にある場合
>は、本来ならば searchdown2 が
>失敗していなければならないのが、なぜか成功扱いになり、しかもカーソルから離
>れた位置にあるはずの行頭の
>改行文字を選択してしまっている状態となっております。
検索範囲の制限していないから、仕様通りの動きだと思いますが?

[ ]
RE:09775 searchdown2でhmonig.dllの\G\x{No.09776
fzok4234 さん 22/03/21 17:27
 
回答ありがとうございます。


> 検索範囲の制限していないから、仕様通りの動きだと思いますが?

確かに、検索範囲を制限するような機能を使用していないため、現在のカーソル位置
よりも右側にずれた場所にある
改行コードにマッチする可能性は考えられます。ただ、仮にそうだとしても、カーソ
ルが 1 行目の行頭に置いた場合に
結果ログの

[1]
Result = 1
BeginLineNo = 4
BeginColumn = 0
EndLineNo = 5
EndColumn = 0

で示されているように、カーソルから最も近い 1 行目の改行文字でもなく、また、
最も遠い文末の 6 行目の改行文字でもなく、
行当たりの文字数が変化する 4 行目の改行文字にマッチすることがちょっと理解で
きません。一体なぜ 4 行目なのか.... 。

おそらく、これは hmonig.dll 側の問題ではなく、秀丸エディタ本体の searchdown2
 側で改行文字を特別扱いするような
何らかの処理が介入しているような感じがいたします。今まで、例えばカーソル位置
の数字を検出する \G\d とかは何の問題もなく
使えていたわけですし、また、検索で改行文字を跨いだ検索を行うには (?#maxline
s:1)(?#fulllinematch) を使わなければならない等、
秀丸エディタで改行文字が特別扱いされていることは既知のことです。

とりあえず、週明けの日中のサイトー企画からの返信を待つことといたします。アド
バイスありがとうございました。



[ ]
RE:09776 searchdown2でhmonig.dllの\G\x{No.09777
h-tom さん 22/03/21 18:20
 
h-tom です。

>で示されているように、カーソルから最も近い 1 行目の改行文字でもなく、また、
>最も遠い文末の 6 行目の改行文字でもなく、
>行当たりの文字数が変化する 4 行目の改行文字にマッチすることがちょっと理解で
>きません。一体なぜ 4 行目なのか.... 。
検索開始位置に改行が来るのが4行目が最初だから。
#カーソルの右が改行かどうか調べるのに、わざわざ検索を使わなくていいと思いま
すが・・。

[ ]
RE:09777 searchdown2でhmonig.dllの\G\x{No.09778
fzok4234 さん 22/03/21 19:26
 
こちらでいろいろテストしたところ、どうやら searchdown2 の仕様がカーソルのあ
る行内で検索に失敗した場合に、
自動的に次の行の行頭にカーソルを移してから改めて検索を行う動作になっているみ
たいです。したがって、例えば
ファイルの内容が

0001 aaaa
0002 bbbb
0003 cccc
0004 dddd
0005 eeee

のときにカーソルを 1 行目の行頭に置いた状態で

searchdown2 @"(?#hmonig)(?#maxlines:1)(?#fulllinematch)(?u)\Gd+" , casesense
 , regular ;

を実行すると、1 行目で不一致なので 2 行目の行頭にカーソルを移して検索して、
不一致なので同様に 3 行目を経て
4 行目で初めてマッチして result が 1 となる動作となり、また、

searchdown2 @"(?#hmonig)(?#maxlines:1)(?#fulllinematch)(?u)\Gf+" , casesense
 , regular ;

を実行すると、1 行目から 5 行目まで再検索を行った全ての行で不一致となって、
ここで初めて result が 0 となる
動作となるようです。


このことに関する詳しい説明がマクロヘルプ

https://help.maruo.co.jp/hidemac/html/080_CmdStatement_Search_searchdialog_searchup_searchdown.html

などに書かれていなかったため、この「行を移して再検索」の動作に全く気付かず、
完全に「罠」にかかった状態となって
おりました。

一応、予め範囲選択して inselect オプションで検索範囲を絞って対処しようと思っ
ています。いろいろアドバイス
ありがとうございました。



[ ]
RE:09778 searchdown2でhmonig.dllの\G\x{No.09779
h-tom さん 22/03/21 20:04
 
h-tom です。

>などに書かれていなかったため、この「行を移して再検索」の動作に全く気付かず、
>完全に「罠」にかかった状態となって
>おりました。
普通に検索しても同じ動作なんですが?

逆に、なんで「カーソル行のみ対象」だと思ったのでしょうか?
(範囲選択・カラーマーカー・部分編集で検索範囲を制限してないのに)

[ ]
RE:09779 searchdown2でhmonig.dllの\G\x{No.09780
fzok4234 さん 22/03/21 20:32
 
> 普通に検索しても同じ動作なんですが?
> 逆に、なんで「カーソル行のみ対象」だと思ったのでしょうか?

\G が常にカーソル位置だけであると誤解していたためです。実際には、その行で見
つからなければ次の行から
再検索となって \G はその新しい行の行頭に設定されます。



[ ]
RE:09780 searchdown2でhmonig.dllの\G\x{No.09785
秀丸担当 さん 22/03/22 17:14
 
\Gは、既にご理解されているように、基本的に行単位で、ヒットが無かったら次の行
の行頭から検索になるということがまずあります。

仕様的には、jre32から続くhmjreの呼び出しでは、\Gに相当する情報は存在しないの
で、その呼び出し方法の互換のhmonigもまた、存在しないということになると思いま
す。
hmonigがどういう処理になっているかはわからないですが、\Gの位置が無いので既定
の処理として1つのマッチに対する検索開始位置になっているという気がします。

ちなみに最近強調表示を拡張できたらいいと思ってLSPを調べようとしたのですが、
どうもLSPによって複雑な言語の強調をしているわけではなさそうで、vscodeやVisua
lStudioなどは、TextMateから始まるtmlanguageという書式でやっているようでした。
これを使うと正規表現だけで多重の入れ子構造を書いて、複雑な文法もできたりする
ようです。
これの対応を検討しています。
この書式の対応自体はある程度はできそうなところまでは来ているのですが、基本的
に鬼車の文法が採用されているようで、既存の定義を使おうとすると、呼び出し方法
で幾つかネックになる点があります。
\Gもその1つで、行頭や1つの検索開始位置とは違う、呼び出し側(秀丸エディタ)が
任意に指定する探索開始位置も必要そうでした。
これらをなんとかするのは、ちょっとすぐにはできなさそうです。

既存の定義を使わずに自前で記述してやるとしたら、ある程度はできるようになるか
もしれません。


[ ]