アーカイブ
難しい言葉で言うと再帰。
正規表現の検索では、普通の検索と違ってたくさんの枝分かれが起こる。
その分かれた枝からさらに別の枝分かれが起こる。
全部の枝を検証して最長一致を求めるっていう事をやらせるために、
TRegExprは再帰っていう方法を使っている。
マッチしているかどうかを判断すべきメソッドは、枝分かれ前の現在の枝しか評価せず、
枝分かれの分岐点からは、それぞれの枝について自分と同じ仕事をするメソッドに託す。
それれぞれの枝がさらに枝分かれすれば、さらに同じ仕事をするメソッドを呼ぶ。
外注が外注するってのを繰り返しながら検索が続くのだが、発注元に内緒の外注になってて、
検索が終わった時点でようやく、最初に発注した人に結果のみを帰すことになるんだが、
1万回くらい外注の外注をやると、発注元に帰れなくなるらしい。
スタックがあふれているらしいが、いまどきスタックなんて言葉を聞くとは思わなかった。
ここがあふれるとかなり致命的なようで、
エラーが出るとか間違った検索をするとかのレベルではなく、アプリが無言で落ちる。
オーバーフローなんて生涯出会わない物と思っていたが、
正規表現だけは簡単にアプリ落としちゃうんだな。
再帰をやるから落ちるんであって、再帰をやめれば落ちないんだから、
再帰以外の方法で正規表現を実装すれば良いんだよな。
でも、枝分かれする物は再帰ってのはもう体で覚えちゃってて、
たとえばGrepとかだと、フォルダの中にフォルダがあるという構造だから、
あたしだって再帰という方法でこれを実装していて、再帰以外ではアイデアが浮かばない。
1万回もフォルダの中にフォルダを作る事はないから、たまたまGrepはうまくいっているし、
おそらく誰が書いてもGrepは再帰だろうよ。
枝が1万回も分かれる事なんて想定出来ないことの方が多いから、
たいがいの人は再帰で落ちるかも知れないとは疑うことなく使ってるんじゃなかろうか。
これを再帰以外でやるってのはもうやたら手間がかかりそうなんだが。
これ別にTRegExprに限った事じゃなくて、別の正規表現エンジンでも落ちる物があるようだ。
k2topからのアクセス急増中で話題のK2Editorも無言で落ちる。
これは確か外部DLLを使うタイプだったはずだから、
それとおなじ派生元のDLLを使うエディタも全滅ということだな。
萌ディタの日記によると、WZEditorもテキストのサイズが大きくなると落ちるってさ。
でも萌ディタは落ちないように作ったみたいだな。EmEditorも落ちない。
この辺が他人の作った物を使って手を抜いてる人種との大きな差だな。
再帰以外の書き方をあえてしているのか、+や*の時だけ特別な処理をしているのか。
やっぱり理解して自分で書いたライブラリじゃないとダメだなぁ。
さて、他人の作ったライブラリで動く真魚は落ちるわけだが、
.NETの正規表現で動くぎょえは同じ方法で落ちずにまともに動く。
なんかもう知力の限界だ。
かしこさのたねとか手にはいるなら狩りに行きたいよ。
ショック。
やっぱり自分で使うライブラリは、ソースコード全部把握してから使わなきゃダメね。
正規表現では+や*とかを使って、ものすごく長い範囲にヒットさせる事が出来るわけだが、
TRegExpで、ものすごく長い文字列にヒットさせようとすると、
オーバーフローが起こって何の警告も出さずにアプリが落ちる事がわかった。
たぶんさ、足し算とか引き算とかで桁があふれた場合は警告出るんだろうね。
今回のオーバーフローは、正規表現ライブラリ内のとあるメソッドが、
そのメソッド自身を呼ぶことで次の文字にもマッチするかを判定しているのがマズく、
落ちた時点まででそのメソッドが自分自身を呼び出した回数は1万数千回と、
なんだか微妙なところでオーバーフローしてるのがさらに困った。
いったいどーすりゃいいんだか途方に暮れてみる。
ユニコード版のスピードが遅いと書いてある理由はおそらく、
Ansi版しかない関数と同名の関数を用意することで対応している部分だろう。
すごく遅そうなユニコード専用部分がいくつか見つかったからな。
それは速い関数を書けばいいだけで問題ではない。
ほかにもユニコードだと遅いっていう理由があるならそっちの方が問題だ。
ともかく大問題は、(.|¥n)+で、カーソル位置から文末までをマッチさせたときなど、
ながーいテキストを探すと必ず落ちるっていうことがいちばんマズい。
出来れば自分で書きたくないので、利用できる物を探してみるのだが、
Delphiであると言うことがどうしても足かせになる。
.NETの正規表現が逆方向も検索できて大変よろしいのだがな。
ともかく、Delphiってのはユニコードがない時代に作られたものなので、
Delphi向けの正規表現といえばSJISしか検索できないとか日本語ダメとかで、
逆にユニコードの検索が出来るとDelphiから利用できなかったりで、
Delphiかつユニコードな正規表現の選択肢は二つにしぼられている。
萌ディタは結局独自で正規表現を書いたようだが、
その前の時点では、同じく二つまで候補を絞っている。
現在真魚に使っているロシアのやつか、ジェダイとかいうチームのやつか。
で、その二つを比べると、結局今使ってる物以上の選択肢はないんだなと。
萌ディタが、このどちらも選択せず、独自で書いた理由は、
>対象となるバッファ構造をよく知る正規表現エンジンじゃないと
ということらしいが、真魚のバッファは検索されるために最適化されているので、
真魚に最適化された正規表現である必要は一切ない。
現在のライブラリのままで、いくらでも改行を挟む検索が出来る。
やはり現在使っているライブラリを元に、
ロシア語は高速でユニコードは低速だと書く理由を探し出して高速化し、
思い通りに動かないような場所を動くように直していくしかないんだろうな。
そうやって作ったとしてもやはり、Delphiを捨てるときに同時に捨てるものであり、
TNotePadの中核部分は開発環境を変えても持って行けるが、
正規表現はもっと優れた物に乗り換えるだろう事を考えるとやる気は起きない。
やっぱり自分で書いて見なきゃ理解も出来ないのかなぁ。
ずっと仕様だからしょうがないとか思ってあきらめてた部分は多々あるわけだが、
その仕様だからってのは、仕様じゃなくすることは出来るけど面倒すぎるって事ばかり。
で、たまたまやる気が持続したので、仕様を打破する更新とか続いたわけだ。
もうさ、不満があったら面倒でも修正しちゃうって流れに完全にシフトしちゃったんだけど、
知識不足でどうしても手が出せないのが正規表現部分。
真魚は作者と嫁が使うために作られた物であり、
作者も嫁もよくわかっていない正規表現が強力に実装される必要性は全くない。
でも、やり方すら書いてないのにやったら出来た的な実装はとても好みなので、
コッソリと強力な正規表現を実装したくなったわけだ。
といっても、現在の実装が強力かどうかすら、あたしにゃ判断できないくらい無知なのだが。
そもそも正規表現を必要とする人が、真魚を使ってみようとも思わないだろうから、
ユーザーから正規表現の不満が出ることはありえないんだけどね。
現在の実装は、TRegExpをちょっぴりだけいじって逆方向に対応した正規表現。
http://regexpstudio.com/
ロシアはDelphiが盛んらしく、これはReadMeがロシア語で書かれていたりして、
あたしがテキストエディタをユニコード化したいと感じた原因になったライブラリの一つ。
で、もともとロシア語を検索するのに最適化された正規表現だが、
ユニコードの検索も出来るということで、現在はこれでうまくいってるなと思う。
だが、ユニコードの検索は遅いよと断りがある点がすごく気になっている。
コードを追いかけても、なぜユニコードだと遅いって言ってるのかわからない。
それがわかるくらいなら、高速化できるように改造出来るんだがね。
後方参照もできるみたいなんだが、置換に生かせないっぽい?とか疑問もあるが、
何せ、よくわからないから手が出せないんだよ。
Perlのサブセット実装だってことはわかったが、Perl自体がわからないしなぁ。
そんな状況なんだが、真魚の内部データはどんな検索にも対応できる実装であり、
Delphiから利用できるもので、かつユニコードに対応したライブラリなら何でもOKなので、
他のライブラリも試してみたいし、それでも不満なら自作もあり得るかなと。
改造で済めばぜひそうしたいが。
面倒だしやりたくないし、全然理解できないけど、それでもやってみたい。