複数行の強調表示でhmonig.dll使用時の不No.39528
fzok4234 さん 22/01/23 20:38
 
いつも大変お世話になっております。


さて、複数行の強調表示の機能で正規表現 DLL に h-tom 氏の hmonig.dll を使用し
て、戻り読みの
「 \K 」を使用したときに強調表示が行われない不具合がありました。


再現手順として、まず以下のような .hilight ファイルを読み込みます。

/<HilightMulti>
/0025,25070002,00,00,00010007,"(?#hmonig)(?u)^[^\\{]*\\K\\{",00010007,"(?#hm
onig)(?u)\\}"
/0019,00000004,00,00,00010007,"(?#hmonig)(?u)a+",00000000,""

これは、
 1.連続する「a」の文字を「単一の文字列」として「スクリプト部分」での色付け。
通常の「強調表示」では
  「スクリプト部分」の色付けができないため止む無く「複数行の強調表示」を使
用した想定。
 2.「行頭から任意の文字列の後の { 」と「 } 」で囲った部分を「複数行」として
「数値」での色付け。
  実際の運用では「 { 」の前の部分の条件を判断する。
の強調表示を意味しています。

そして、以下の内容のテストファイルを開きます。

0001  aaaa
0002  { bbbb }
0003  aaaa { bbbb }

すると、1 行目の「aaaa」は「スクリプト部分」の色に、2 行目の「{ bbbb }」は
「数値」の色に確かに
強調表示されます。しかし、3 行目の「aaaa」は「スクリプト部分」の色になるもの
の、「{ bbbb }」は
何も色付けされません。

つまり、「{ bbbb }」を定義した上記 2. の定義で「 \K 」の左側の部分に、上記 1.
 で定義された
「aaaa」が含まれていると上記 2. の定義が動作しなくなってしまうということです。


このように、複数行の強調表示の機能においては「 \K 」の左側に、たとえ「単一の
文字列」だとしても
「複数行の強調表示」で既に色付けされた文字列があると動作しなくなってしまいま
す。このため、
「 \K 」の左側に別の「複数行の強調表示」された文字列が来ないようしなければな
らないという
大きな制約が発生してしまって大変困っています。

なお、「 \K 」の左側に通常の「強調表示」で色付けされた文字列がある場合にはこ
の不具合は発生しません。
しかし、通常の「強調表示」では「スクリプト部分」や「数値」などの色付けができ
ず、どうしても
「複数行の強調表示」の「単一の文字列」も使用しないといけないため、全面的に通
常の「強調表示」に
置き換えることはまず不可能です。


環境は、

秀丸エディタ : 9.12β4 Float x64
hmonig.dll : 0.8.7.0

です。





[ ]
RE:39528 複数行の強調表示でhmonig.dll使No.39529
h-tom さん 22/01/23 22:36
 
h-tom です。

>さて、複数行の強調表示の機能で正規表現 DLL に h-tom 氏の hmonig.dll を使用
>して、戻り読みの
>「 \K 」を使用したときに強調表示が行われない不具合がありました。
検索開始位置の関係でマッチしていないだけなので、\Kの有無は関係ないですよ。

[ ]
RE:39529 複数行の強調表示でhmonig.dll使No.39530
fzok4234 さん 22/01/24 01:45
 
回答ありがとうございます。


> 検索開始位置の関係でマッチしていないだけなので、\Kの有無は関係ないですよ。

おかげさまで問題の焦点がはっきりしてきました。どうやら「複数行の強調表示」で
既に色付けされた
文字列は、新たに「複数行の強調表示」の実行での検索開始位置から除外されるよう
です。

これが先に色付けした方と後から色付けする方の両方が「複数行」のモードなら、複
数行の「入れ子」の
関係が成立する場合に限定して「重ねる」ことを許可して、「入れ子」関係が成立し
ない「重なり」を
不許可にすることは理解できます。

しかし、先に色付けした方が単なる「単一の文字列」のモードでも「重なり」を排除
してしまうのは
少しおかしい気がします。というのは、先に色付けした方が「通常の強調表示」の場
合はちゃんと
「重なり」が許可されているからです。用途から見れば、「単一の文字列」と「通常
の強調表示」は
ほとんど同じ用途で使われるものだから、このような差異はなるべくない方がよいと
思われます。


そもそも、なぜ「通常の強調表示」ではなく「単一の文字列」を使用するのかといえ
ば、「単一の文字列」に
ある全ての強調表示の種類が「通常の強調表示」では使えないからです。「単一の文
字列」では、

・強調表示 1 - 8
・行の強調表示 1 - 4
・特に強調表示 1 - 4

に加えて

・普通の文字
・スクリプト部分
・数値
・文字定数
・コメント
・#ifdef等での無効部分

の 6 種類が使用可能ですが、「通常の強調表示」ではこの 6 種類が存在しません。
これらを使用するためには
どうしても「単一の文字列」を使用しなければならなくなっています。


もし要望があるとすれば、

 1.「複数行の強調表示」同士の「重なり」においては、「入れ子」関係のある「複
数行」同士を除いて原則
  許可する。
 2.それが技術的に困難ならば、「通常の強調表示」で上記の 6 種類を追加する。

といったところです。


(参考)

.hilight ファイル :

49,(?#hmonig)(?u)c+
/<HilightMulti>
/0025,25070002,00,00,00010007,"(?#hmonig)(?u)^[^\\{]*\\K\\{",00010007,"(?#hm
onig)(?u)\\}"
/0019,00000004,00,00,00010007,"(?#hmonig)(?u)a+",00000000,""

開いたファイル :

0001  aaaa { bbbb }
0002  cccc { bbbb }

結果 :
1 行目の「aaaa」     : 〇 「スクリプト部分」で色付け
1 行目の「{ bbbb }」 : × 色付けされず
2 行目の「cccc」     : 〇 「強調表示 1」で色付け
2 行目の「{ bbbb }」 : 〇 「数値」で色付け



[ ]
RE:39530 複数行の強調表示でhmonig.dll使No.39532
秀丸担当 さん 22/01/24 10:00
 
perl互換の\Kの動作について調べてみたところ、前方一致のような戻り読みというよ
り、参照するテキストは検索開始位置から戻らず、ヒット位置をそこにするという動
作のようです。

ファイルタイプ別の設定の強調表示で、hmonigで「...\K[xyz]」としても、
123x23y3z
というテキストでyは強調されないので、重なりの問題としては、強調表示でも同じ
のようです。

この場合、前方一致で(?<=...)[xyz]のように書くと、検索開始位置から戻った位置
も調べるので、前方一致のほうがいいと思います。
検索開始位置は順に進みながらも、前の方も見ます。

hmonigの場合、前方一致であれば問題無いですが、なぜか前方一致に*や+があると正
規表現の解釈エラーになるようでした。
hmjreの場合は、前方一致でもできます。
ただし強調表示で前方一致の制限があるので、(?#lookbehind)を付けて制限を解除す
る必要があります。
hmjreで(?#lookbehind)(?<=...)[xyz]のようにするといいと思います。

[ ]
RE:39532 複数行の強調表示でhmonig.dll使No.39533
fzok4234 さん 22/01/24 13:49
 
> hmonigの場合、前方一致であれば問題無いですが、なぜか前方一致に*や+があると
>正規表現の
> 解釈エラーになるようでした。

hmonig.dll の (?<=) および (?<!) では * や + などの可変長文字列が使用できず、
固定長文字列のみ
使用可能なのは 鬼雲 の使用です。

参考 : https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja


それから、問題の焦点は 鬼雲 の \K の仕様云々ではなく、

 1. 「複数行の強調表示」の「単一の文字列」が他の「複数行の強調表示」との
「重なり」を許可しないこと。
   「通常の強調表示」同士や「通常の強調表示」と「複数行の強調表示」との重
なりは許可されている。
 2. 「複数行の強調表示」で使える
    ・普通の文字
    ・スクリプト部分
    ・数値
    ・文字定数
    ・コメント
    ・#ifdef等での無効部分
   の 6 種類の強調表示の種類が「通常の強調表示」では使用できないこと。そ
のため、やむなく「複数行の強調表示」の
   「単一の文字列」で代替せざるを得ないこと。

にあるといえます。いずれも当方において複雑な .hilight ファイルの記述を妨げる
大変大きな障害となって
おります。


上記 1. については正規表現無しでも簡単に不具合を再現できました。.hilight フ
ァイル

129,重なり通常の強調表示
65,通常の強調表示重なり
/<HilightMulti>
/0016,00000004,00,00,00000002,"重なり単一の文字列",00000000,""
/0007,00000004,00,00,00000002,"単一の文字列重なり",00000000,""

を適用したうえで、ファイル

0001  通常の強調表示重なり通常の強調表示
0002  通常の強調表示重なり単一の文字列
0003  単一の文字列重なり通常の強調表示
0004  単一の文字列重なり単一の文字列

を開いた結果、

1 行目の左側の「通常の強調表示」       : 〇 「強調表示 2」で色付け
1 行目の右側の「重なり通常の強調表示」 : 〇 「強調表示 3」で色付け
2 行目の左側の「通常の強調表示」       : 〇 「強調表示 2」で色付け
2 行目の右側の「重なり単一の文字列」   : 〇 「強調表示 3」で色付け
3 行目の左側の「単一の文字列」         : 〇 「強調表示 2」で色付け
3 行目の右側の「重なり通常の強調表示」 : 〇 「強調表示 3」で色付け
4 行目の左側の「単一の文字列重なり」   : 〇 「強調表示 2」で色付け
4 行目の右側の「単一の文字列」         : × 色付けされず

となり、結果をまとめると、

 A. 「通常の強調表示」同士の重なりは許可される。
 B. 「通常の強調表示」に「複数行の強調表示」を重ねることも許可される。
 C. 「複数行の強調表示」に「通常の強調表示」を重ねることも許可される。
 D. 「複数行の強調表示」同士の重なりは許可されない。

ということになります。


上記 D. については、「複数行の強調表示」の中の「複数行」と「次の行から色付
け」に関しては
強調表示の「入れ子」構造を維持する上で「入れ子」関係の成立しない重なりを許可
しないことは
理解できます。しかし、用途がほとんど「通常の強調表示」と変わらない「単一行
(行末まで)」と
「単一の文字列」に関して、このような重なりを許可しないことは何の意味もなく、
正に
「百害あって一利なし」の状態です。

このことから、不具合修正の要望は、

 1. 「複数行の強調表示」の中の「単一行(行末まで)」と「単一の文字列」では重
なりを許可する。
 2. 「通常の強調表示」で使用可能な種類に
    ・普通の文字
    ・スクリプト部分
    ・数値
    ・文字定数
    ・コメント
    ・#ifdef等での無効部分
   の 6 種類を追加する。

の 2 つといたします。どうかよろしくお願いします。



[ ]
RE:39533 複数行の強調表示でhmonig.dll使No.39534
fzok4234 さん 22/01/24 13:51
 
[訂正]

4 行目 :
× 使用可能なのは 鬼雲 の使用です。
〇 使用可能なのは 鬼雲 の仕様です。


[ ]
RE:39534 複数行の強調表示でhmonig.dll使No.39537
秀丸担当 さん 22/01/24 16:47
 
通常の強調表示については、必ずしも重複が許可されるものではないと思っていまし
たが、調べてみたところ、正規表現で自分自身のヒットする範囲に重複する場合のみ
許可せず、他は許可していました。
例えば正規表現で「通常の強調表示重なり|重なり通常の強調表示」は許可されない
です。
それ以外は許可されています。
重複がある場合は、[その他]→[ファイルタイプ別の設定]→[デザイン]の一覧の優先
順位になります。
たぶんですが、昔に正規表現が遅いという前提があってそういう仕様になっていたか
もしれず、今は自分自身に重複できるように変更してもいいかもしれません。

複数行のユーザー定義は、重複は無く、一覧の上の方が優先順位が高いです。
「↑」「↓」ボタンで優先順位を変更できます。(優先順位の操作についてヘルプが
無かったので追記します)
重複できるようにすると、一覧の順序は関係無くなって動作が変わるので、別のオプ
ションの追加が必要かもしれません。

コメントや文字列などの意味のある種類は、現状では、複数行の強調かcolormarker
のみで指定できます。
例えば検索の「追加の条件」で意味を持つようになります。
通常の強調表示も意味のある条件に含めると、例えば「特に強調」が上に覆いかぶさ
ったりすると良くないので、そのあたりをうまくやる必要があると思います。複数行
の強調で重複がある場合も同様です。
現状複数行の強調だけに分かれている処理が、混在して分解して4つになりそうな感
じです。
だいぶん複雑なので、前方一致でできればそれに越したことは無いと思いますが、そ
ういうことができたらいいご要望があるということで、参考にさせていただきます。

[ ]
RE:39537 複数行の強調表示でhmonig.dll使No.39543
fzok4234 さん 22/01/25 04:08
 
> 複数行のユーザー定義は、重複は無く、一覧の上の方が優先順位が高いです。
> 「↑」「↓」ボタンで優先順位を変更できます。(優先順位の操作についてヘルプ
>が無かったので追記します)
> 重複できるようにすると、一覧の順序は関係無くなって動作が変わるので、
> 別のオプションの追加が必要かもしれません。

強調表示の重なりの部分は ↑↓ ボタンで並べた優先順位の「高い」方で色付けする
方法でよいと
思います。例えばファイルの内容が

0001  aaaa重なりbbbb

のとき、複数行の強調表示ダイアログの項目が

 1. 文字列 = "aaaa重なり" , 種類 = 「強調表示 1」
 2. 文字列 = "重なりbbbb" , 種類 = 「強調表示 2」

の順番なら

"aaaa重なり" : 「強調表示 1」
"bbbb"       : 「強調表示 2」

で色付けされ、

 1. 文字列 = "重なりbbbb" , 種類 = 「強調表示 2」
 2. 文字列 = "aaaa重なり" , 種類 = 「強調表示 1」

と順番を入れ替えたなら

"aaaa"       : 「強調表示 1」
"重なりbbbb" : 「強調表示 2」

と色付けされる、といった具合です。いずれにせよ、優先順位に従って「必ず」色付
けを行うことが
重要であり、重なりがあるだけで後からの色付けを「放棄」することだけは絶対に避
けることです。


> 通常の強調表示も意味のある条件に含めると、例えば「特に強調」が上に覆いかぶ
>さったりすると
> 良くないので、そのあたりをうまくやる必要があると思います。

そもそも「特に強調表示 1 - 4」自体が「文字定数」や「コメント」などの中にある
特定の重要なキーワードを
抜き出して強調表示させる役割があるため、逆に「文字定数」や「コメント」などの
上に覆いかぶさってくれないと
困る気がしますが ...。

例えば、ファイルの内容が

0001  ccccddddeeee

で、通常の強調表示の定義が

 1. 文字列 = "ccccddddeeee" , 種類 = 「コメント」
 2. 文字列 = "dddd"         , 種類 = 「特に強調表示 1」

の場合には、

"cccc" : 「コメント」
"dddd" : 「特に強調表示 1」
"eeee" : 「コメント」

のように分断するような扱いをせずに、

"ccccddddeeee" : 「コメント」
"dddd"         : 「特に強調表示 1」

という風に強調表示の項目の定義ごとに完全に「別レイヤー」として扱えば問題は起
きないはずです。


> だいぶん複雑なので、前方一致でできればそれに越したことは無いと思いますが、

残念ながら、前方一致 / 不一致の (?<=) / (?<!) を使用する目的だけで正規表現 D
LL を
HmJre.dll に限定するわけにはいかない実情があります。

まず、Unicode の文字プロパティ \p{property-name} で特定の文字種に確実にマッ
チさせたり、
高速化のために無駄なバックトラックを排除するためのアトミックグループ (?>) や
強欲 *+ を
使用する必要があるため、この機能を持った hmonig.dll がどうしても必要になりま
す。

加えて、このフォーラムの直近のやり取りを見てもわかるように、HmJre.dll には主
に部分式呼び出しに
関するバグが頻発しています。昨日も https://www.maruo.co.jp/hidesoft/2/x39535_.html?a=2#39535
 で
提示したように保護違反で秀丸エディタごと落ちる大バグがあったばかりです。この
ような状況のため、
安定した部分式呼び出しの機能を使うためにも hmonig.dll が欠かせない状態となっ
ています。

このような実情があるため、前方一致の代替としてどうしても hmonig.dll の \K を
使わざるを得ません。
ここに、\K の左側の部分と既に強調表示済みの部分との衝突問題が発生して、.hili
ght ファイルの
正しい動作を大きく妨げる障害が引き起こされたということです。



[ ]
RE:39543 複数行の強調表示でhmonig.dll使No.39546
秀丸担当 さん 22/01/25 15:45
 
今の複数行の強調の優先順位は、色の重なりというより、そもそもの条件を判断する
優先順位になっています。
例えば開始文字列「<」と開始文字列「<!--」があったとして、「<!--」は上に持っ
てこないとできないです。
単一の文字列も同様で、「<!--.*?-->」とあったとしたら上に持ってこないといけな
いです。
そうやってテキストの先頭から末尾に向かって順に処理されていくのが、複数行の強
調の性質です。
そういうこともヘルプに書いておこうと思います。
重複をやるとすると、別の性質になるので仮にオプションにするとして、そうすると
同じ一覧上にありながら別次元のものが混在するということになります。
普通の強調表示でも、同じ一覧にありながら別次元のものが混在することになるだろ
うということです。
だいたい言われていることと同じです。
できないよりかはできたほうがいいと思います。
そういうご要望があるということで、参考にします。

あと、通常の強調の正規表現の自分自身の重なりは、できてもよさそうかと思ったの
ですが、「.*」でやると長いテキスト全体を文字数分だけ繰り返してしまうので、今
はキャッシュができたとはいえ、負荷が大きそうなのでやめておこうと思います。

[ ]