[要望]正規表現の部分式呼び出しNo.38878
fzok4234 さん 21/04/15 14:48
 
お世話になっております。

さて、現在秀丸エディタ上でHmJre.dllで正規表現を使う際に大きな問題が起きてい
ます。
それは、正規表現の「式自体」を記憶して繰り返し/再帰的に実行できないことです。
このため、
  1. 同じ正規表現式を何度も繰り返して書かなくてはならない。
  2. 入れ子になった括弧などに正しくマッチできない。
という悩みを当方で抱えています。

1.については例えば
  19.68.2340.3.6512.3245.9021.45321.5
というような任意個数の.区切りの数字にマッチさせるために
  ^([0-9]+)(\.([0-9]+))*$
とする必要があるのですが、問題なのは、
  19

  68
などの数字部分にマッチする
  ([0-9]+)
を同じ式内に2回書かないといけないことです。また、マクロ内や.hilightファイル内で
  19.68.2340.3.6512.3245.9021.45321.5
などと、この形式を内包した
  (234.5.67.89),(101.34.321098)
などにマッチする正規表現式を別々のステートメントや行に書く必要があるときに、
それぞれ
  ^(([0-9]+)(\.([0-9]+))*)$

  ^\((([0-9]+)(\.([0-9]+))*)\),\((([0-9]+)(\.([0-9]+))*)\)$
にする必要があるのですが、やはり
  (([0-9]+)(\.([0-9]+))*)
を3回、
  ([0-9]+)
に至っては3*2=6回も書かないといけません。このことにより、
  ・同じ式をミスなくコピペするのが大変。
  ・式の修正の際に一度に全て書き換えなければならない。
という開発や保守に大きな支障をきたす「DRY原則違反」の状態となってしまいます。
また、
式が肥大化して強調表示の3999文字などの文字数制限に簡単に引っかかってしまいま
す。

2.ついては、過去の投稿でも申しましたが、
  <<qwer>,abc,<def,<wsd,rfv>>>
というような括弧の入れ子構造にマッチさせるためには、「括弧にマッチする式」自
体に
自分自身を内包した再帰式を定義しなければならず、そのためには式を記憶して、い
つでも
その式を実行できる機能が絶対に必要です。

そこで要望があるのですが、式自体に名前を付けて一旦記憶し、その後はいつでも名
前を
使ってその式を実行する「部分式呼び出し」を実装してもらえれば大変助かります。

部分式呼び出しのサポートは既にRuby言語の正規表現エンジン
  https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html#subexp
や鬼雲
  https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja
などで広く行われています。

鬼雲に関しては、h-tom氏による「hmonig.dll」が秀丸エディタの正規表現エンジン
として
使用可能なのですが、部分式が使えるスコープはそれを定義した1つの式中のみであり、
マクロの複数の文や.hilightファイルの各行に書かれた複数の式を跨いでの実行はで
きません。

そこで、秀丸エディタ本体側で行やマクロ実行単位やウィンドウ(タブモードならタ
ブ)を
跨いだスコープで使用可能な部分式呼び出しが有ればと思っています。具体的には
  1. 1つの正規表現式の中だけ。例えば検索/置換/GREPの1回の実行だけとか、マクロの
     setsearchの1回の実行だけとか、.hilightファイルの1行内だけとか。
  2. マクロの1回の実行内や.hilightファイル1個内。マクロの場合はsetsearchなど
で部分式に
     名前を付ける式を1回実行すれば別の文上では名前で呼び出す式だけで実行可能。
     .hilightファイルではある行で部分式に名前を付ける式を書いておけばそれ以
降の行で
     その部分式を呼び出せる。
  3. 秀丸エディタのプロセス単位。例えば、検索/置換/GREPで一度部分式に名前を
付ける式を
     実行すれば、以降そのウインドウ(タブ)上のマクロであれ強調表示であれその
部分式を
     呼び出せる。
  4. 全ての秀丸エディタ。あるウインドウ(タブ)上で一度部分式に名前を付ける式
を実行すれば
     他のウインドウ(タブ)でも使用可能になる。
の4段階ぐらいのスコープを用意してもらえれば助かります。具体的な構文の案として、
  (?<name,scope>式)
で式を記憶して
  \G<name>
で呼び出すというような感じです。

どうかよろしくお願いします。


[ ]
RE:38878 [要望]正規表現の部分式呼び出しNo.38879
h-tom さん 21/04/15 23:05
 
h-tom です。

自前で、正規表現パターンに特定文字列があった場合、特定正規表現に置換して検索
用DLLに渡すラッパーDLL作った方が早いと思いますよ。

[ ]
RE:38879 [要望]正規表現の部分式呼び出しNo.38880
fzok4234 さん 21/04/15 23:48
 
解決策の提案ありがとうございます。

一応、当方においてHmJre.dllやhmonig.dllを直接操作しようと考えたことが
ありました。しかし、実際にこれを実行しようとしたときに3つの大きな問題に
遭遇しました。1つは「1文字」の定義が秀丸マクロと各DLLとで異なること、
もう1つは検索結果を表す「文字の範囲の仕方」がやはり秀丸マクロと各DLLとで
異なることです。
「1文字」の定義はこちらから何度も要望を出した結果、DLLでの「バイト数」と
マクロでの「UTF-16コード数」や「書記素クラスター数」との変換関数が
そろってきました。しかし、「文字の範囲の仕方」についてはDLLでの
「開始オフセットと長さ」とマクロでの「開始行、開始桁、終了行、終了桁」との
相互変換手段が未だ提供されていない状態です。このため、もしDLLの直接操作を
行いたいならファイルの先頭からの各行の文字数を加算する処理が不可欠となり、
大きなファイルでの動作が極めて重くなってしまうことが予想されます。
3つ目の問題はDLLを使い慣れたマネージド実行系のC#とこみやんま氏の
HM.NET.dllで扱う際のP/Invokeの属性設定がDLLのドキュメントに無いことで、
実行の仕方がまだよくわからないことです。

これらの問題のためにDLLの直接操作は敷居が高いのが現状です。



[ ]
RE:38880 [要望]正規表現の部分式呼び出しNo.38881
秀丸担当 さん 21/04/16 08:49
 

正規表現の再利用がしたいとのことで、正規表現の文法を拡張するか、秀丸エディタ
独自のこととして扱うかは完全に別のこととして考えたほうがいいと思います。
やるかどうかはまだ何とも言えないですが、秀丸エディタ独自のこととしてやるとし
たら、独自のコメント記述で(?#maxlines:n)とかあるように、コメントを独自に解釈
するのであれば一応ありだとは思います。
例えば、(?#<NAME>(abc|123))として記憶し、(?#g<NAME>)と書かれていたら記憶され
たものを展開するとかです。
ただ秀丸エディタ独自の展開であれば、1つの正規表現の中での入れ子(再帰呼び出
し)は無限になってしまうのでできないです。
やるとしたら、
・1つ正規表現内(ただし入れ子はできない)
・同じhilight定義内
・同じマクロ内
は、ありだと思います。

・同じプロセス内
・全ての秀丸エディタ
は、無理があるというか、どういう順番で処理するかにもよるし、ダイナミックに変
化することを想定されたら大変だと思います。

同じhilightやマクロ内で完結しているのは再利用の効果があると思いますが、変化
しうる外的要因に依存するのは悪影響のほうが強いのではないかと思います。
マクロ内の場合もマクロで完結すればありかと思ったのですが、どこまで影響を与え
る/与えないとか、hilightには影響しないほうがいいとか考えると、いざやるとなる
と困難があるかもしれないです。
そうなると実用的なのはhilightくらいになってしまうかもしれません。
どこでも常に利用できるとすると、h-tomさんの言われるようにラッパーDLLを作って
しまうと可能だとは思います。(ただDLLを作るのはそれはそれで大変だと思います)

ちなみに、getlinecount関数で改行を含んだ文字列から行と桁に変換する方法がV8.9
4で追加されています。
相互変換としてはHmJre用ですが、charindex_to_byteindexとbyteindex_to_charinde
x、またはHmJreのdllfuncの関数でSetUnicodeIndexAutoConvertがあります。

[ ]
RE:38881 [要望]正規表現の部分式呼び出しNo.38882
fzok4234 さん 21/04/16 09:58
 
回答ありがとうございます。

> ただ秀丸エディタ独自の展開であれば、1つの正規表現の中での入れ子(再帰呼び
>出し)は
> 無限になってしまうのでできないです。

とのことですが、Rubyであれ鬼雲であれ無限ループのリスクは必ずあるはずです。
ユーザーは
このリスクを承知の上で正しい終了条件を設定して使用することになります。

もしユーザーの誤った終了条件が原因で秀丸エディタ本体がスタックオーバーフローで
クラッシュする問題が生じるのを恐れているならば、
  ・括弧などの入れ子構造のみにマッチする専用のメタ文字を新たに設ける。ユー
ザーは
    終了条件を考えなくてもよい。
  ・ユーザーに入れ子の最大深さの指定を強制させて再帰呼び出しを可能にする。
  ・再帰呼び出しの機能のON/OFFを「動作環境」または「ファイルタイプ別の設定」
で切り替え
    られるようにする。もちろんデフォルトはOFFで。ONにするときに無限ループの
危険性を
    伝える警告メッセージボックスを出してユーザーの同意を求める。
といった対策を講じればよいと思います。

> ・同じプロセス内
> ・全ての秀丸エディタ
> は、無理があるというか、どういう順番で処理するかにもよるし、ダイナミックに
>変化することを
> 想定されたら大変だと思います。
> 同じhilightやマクロ内で完結しているのは再利用の効果があると思いますが、変
>化しうる外的要因に
> 依存するのは悪影響のほうが強いのではないかと思います。

一応私の理想として、秀丸エディタで最初にファイルを開くときに「自動起動マク
ロ」の「ファイルを
開いた直後」を使ってマクロや強調表示などで使用する正規表現式を一気にメモリに
登録して、その後は
ほぼ読み取りのみで式にアクセスして実行する、といった運用を構想していました。
つまり、「最初に
正規表現式を決めたら後は変更しない」という前提です。

・同じプロセス内
・全ての秀丸エディタ
に関しては正規表現の評価の形ではなく「ファイルタイプ別の設定」などで設定とし
て指定する方式の
ほうがよいかもしれません。

> ちなみに、getlinecount関数で改行を含んだ文字列から行と桁に変換する方法がV8.
>94で追加されています。

確かにヘルプの見落としでした(^^;)
これから大きなファイルを開いた状態でgettextで全文を取得してgetlinecountに渡
して、所要時間が
どれくらいかかるかベンチマークを取ろうと思っています。



[ ]
RE:38882 [要望]正規表現の部分式呼び出しNo.38883
秀丸担当 さん 21/04/16 11:14
 

秀丸エディタ独自の展開でやるとすれば、ただの元の正規表現文字列の置換でしかな
いので、無限に長い正規表現文字列が生成されてしまうということです。
回数制限があればいいのかもしれないですが、入れ子にしたら最後の展開が(xxx|(?#
g<NAME>))だとして、(xxx|)のように空になるので、期待とは違うことになるのでは
ないかとも思います。

一度定義したものを固定で、どこでも通用するようにするとしたら、h-tomさんの言
われるようにラッパーDLLを作ってしまうのがいいのかもしれません。

getlinecount関数は、たぶん相当遅いと思います。
全部のテキストを渡して正規表現で調べるたびに毎回全部変換というのは、やめたほ
うがいいというか、無理な使い方と思ってもらった方がいいと思います。

[ ]
RE:38883 [要望]正規表現の部分式呼び出しNo.38884
fzok4234 さん 21/04/16 12:55
 
> 秀丸エディタ独自の展開でやるとすれば、ただの元の正規表現文字列の置換でしか
>ないので、
> 無限に長い正規表現文字列が生成されてしまうということです。
> 回数制限があればいいのかもしれないですが、入れ子にしたら最後の展開が(xxx|
>(?#g<NAME>))だとして、
> (xxx|)のように空になるので、期待とは違うことになるのではないかとも思います。

秀丸エディタ本体「だけ」で対応させると単純な文字列置換で行うしかないのでどう
しても
そうなってしまいます。

ちゃんと対応させるためには「秀丸エディタ本体」と「HmJre.dll」の双方の改修が
必要になります。
  ・まず、HmJre.dll単体で部分式呼び出しのメタ文字をしっかりと実装する。
  ・部分式の記憶自体はHmJre.dllが行う。つまり、部分式はHmJre.dllが管轄するメ
モリに保存
    される。
  ・このメモリは
      1. 1つの正規表現用
      2. 同じマクロ/.hilight用
    の2つ用意される。
  ・次に、秀丸エディタ本体にて現在実行中のマクロ/.hilightのインスタンスを一
意に識別する
    IDを生成して保持するようにする。
  ・秀丸エディタ本体はHmJre.dllを使用する際にその都度このIDをHmJre.dllに向け
て送信する。
  ・HmJre.dllはこのIDを受信して上記2.のメモリにこのIDと関連付けられた部分式
保存用のコンテナ
    を作成する。つまり、2.のメモリはIDをキー、コンテナを値とするハッシュテー
ブルとなる。
    そして部分式をこのコンテナに保存する。
  ・秀丸エディタ本体から\g<NAME>で部分式の実行リクエストがIDとともに届いたら
そのIDのコンテナ
    内の部分式を実行する。
という処理の流れにした方がよいのではと考えました。つまり、「同じマクロ/.hili
ght内」の部分式
の機能は専ら「秀丸エディタ本体とHmJre.dllとの組み合わせ」限定の特別なもので
あり、秀丸エディタ本体から
他の正規表現DLLをした場合には機能しません。また、HmJre.dllを秀丸エディタ以外
から使用する場合も
「1つの正規表現内」限定の部分式が使用可能となります。

そもそもHmJre.dll自体に、例えば「Unicodeプロパティ指定の文字クラス」の実装と
いった機能強化すべき点が
たくさんあります。他の正規表現DLLにユーザーが流れないよう日々精進に励むこと
を切に願っております。



[ ]
RE:38884 [要望]正規表現の部分式呼び出しNo.38885
秀丸担当 さん 21/04/16 15:01
 

HmJreの拡張として、(?<NAME>pattern)と\g<NAME>のような書き方と、入れ子の再帰
呼び出しも対応できたらいいと思います。秀まるおにも知らせておきます。
それはそれでできたらいいとして、秀丸エディタと密接に絡むのはあまり良くないと
思います。
当初はfzok4234さんも書かれているように、HmJreを拡張した上で、それに合わせる
形で秀丸エディタ本体ができる方法は無いかと思ったのですが、複雑すぎるのと、特
定の範囲に完結しなくて依存関係があるのは問題になりやすいと思います。
秀丸エディタ本体でやるとしたら、いろいろスコープが案がありましたが、主にhili
ght内だけで完結するのがいいと思います。
とはいえ、本当に期待されているであろうことは、固定のものを用意して、hilight
に限らずどこでも簡略表記できるようにすることだと思うので、それだったらラッ
パーDLLが合理的かなと思います。

なので、HmJreは拡張できたらいい、ということと、それとは別にラッパーDLLで簡略
表記をカスタマイズできるようにする、ということがいいかもしれません。
でもラッパーDLLを1から作るのはたぶん大変だと思います。
一応手元にはひな形に近いものはあるのですが、それを公開できる形にできるかはち
ょっと検討する必要がありそうなので、もうちょっと考えます。

[ ]
RE:38885 [要望]正規表現の部分式呼び出しNo.38886
fzok4234 さん 21/04/16 18:45
 
対応の検討ありがとうございます。

> それはそれでできたらいいとして、秀丸エディタと密接に絡むのはあまり良くない
>と思います。
> 当初はfzok4234さんも書かれているように、HmJreを拡張した上で、それに合わせ
>る形で
> 秀丸エディタ本体ができる方法は無いかと思ったのですが、複雑すぎるのと、特定
>の範囲に
> 完結しなくて依存関係があるのは問題になりやすいと思います。

確かに、秀丸エディタ本体とHmJre.dllは物理的に別コンポーネントのため「疎結
合」のほうが
よいはずです。しかし、「別コンポーネント」であるがゆえに融通が利かない状態に
なっているなら
あえて「密結合」にして対処したほうがよいのではと思った次第であります。

もし、仮に実際に双方を密結合させるなら「動作環境」で従来の動作か新しい密結合
な動作かを
ユーザーが選択できるようにすればよいと思います。

> 本当に期待されているであろうことは、固定のものを用意して、hilightに限らず
> どこでも簡略表記できるようにすることだと思うので、それだったらラッパーDLLが
> 合理的かなと思います。

一応、以前からhmonig.dllを使って特定のパターンの文字を選択し、カラーマーカー
機能で、
色付けを行う「強調表示もどき」DLLの制作をC#とHm.NET.DLLを使って行うことを検
討して
いるところでございます。
しかし、プロセスを跨いで全ての秀丸エディタに同じ値を供給する仕組みを自前で作
るには、
1つのDLLファイルでは済まなくて全プロセスがプロセス間通信でアクセスする
EXEファイル「IPCサーバーアプリ」も作らなくてはならず、このIPCサーバー自体の
動作管理
の実装が非常に難しいのでプロジェクトが頓挫気味となっています。
また、この強調表示もどきDLLを本物の.hilightと同じ感覚で使うためには、DLLを呼
び出す
マクロファイルを「自動起動マクロ」の「編集後タイマー」に登録して1文字入力す
るたびに
自動実行させる必要があります。このため「動作が軽い」ことが絶対条件なため検索
の正確さと
パフォーマンスとの両立をどうすべきか悩むところであります。

ただ、DLLを自作する場合であってもDLLの中からマクロのsetsearchなどを利用する
ことも
考えられます。そこで大きな問題になるのはsetsearchなどの正規表現文字列にある
「文字数制限」
です。現時点で4095文字に制限されていることから、DLLの中でひたすら部分式の文
字列値を
連結して変数に格納した正規表現をsetsearchなどにそのまま渡すのはリスクを伴い
ます。文字数の
節約のためにはやはり、正規表現エンジン側での部分式の記憶機能に頼らないといけ
ないようです。



[ ]
RE:38886 [要望]正規表現の部分式呼び出しNo.38887
秀丸担当 さん 21/04/19 13:55
 

ラッパーDLLのひな形を用意しようかと思ったのですが、さらに作りこんでもらうの
は大変そうで、やっぱり簡単に置換できるDLLを作成してみました。
ライブラリからダウンロードできます。
https://hide.maruo.co.jp/lib/macro/hmjreselect010.html
これだと全般的に置換できて、再利用というか固定のパターンを簡略して書けたりし
ます。
\g<NAME>でもいいですが、何でも適当な置換の設定をしておけます。
例えば
\X=(([0-9]+)(\.([0-9]+))*)
と設定しておいて、
^\((([0-9]+)(\.([0-9]+))*)\),\((([0-9]+)(\.([0-9]+))*)\)$

^\(\X\),\(\X\)$
といった感じに簡略表記できます。ただ入れ子はできないです。
DLLの選択機能もあって、1つだけhmonig.dllを使ったりもできます。

[ ]
RE:38887 [要望]正規表現の部分式呼び出しNo.38888
fzok4234 さん 21/04/19 18:18
 
迅速な対応ありがとうございます !!

わざわざ個別DLLを作ってくれるなんて、もう感謝の言葉も見つかりません。
これでマクロや.hilightの文字数制限に引っかかるリスクをかなり回避できそうです。

本当にありがとうございました。


[ ]