hmjre.dllの正規表現の基本ルールについてNo.07864
colder さん 13/04/17 14:12
 
colderです

hmjreにおける正規表現を解釈する基本的なルールはどのようになっているのですか?

様々なツールで使われている正規表現はサポートされているメタ文字や
その解釈方法によりたくさんの方言がありますが、
基本的なルールは以下の三種類に大別されるかと思います。
(1) とにかく一番長い文字列にマッチ
(2) 一番長い文字列にマッチ+左側の正規表現ができる限り長くなるようにマッチ
(3) 左側の正規表現ができる限り長く文字列にマッチするようにマッチ

で、hmjreの正規表現はこの三つのどれにも当てはまらないようなのです。

(1)はAWKなどで使われているルールで、基本的に後方参照をサポートしていません。
(少なくとも、私の知る限り、後方参照をサポートしているツールはありません。)
(2)はsedなどで使われているルールです。
(3)はPerl、javascriptなどで使われているルールで、必ずしも最長の文字列にマッ
チしないという特徴があります。

(a) (3)のルールでは正規表現"a+([ab]b)+"が文字列"aaabbb"の最初の5文字にマッチ
(1や2のルールでは6文字にマッチ)する
(b) (3)のルールの正規表現のみが*?, +?などのものぐさマッチをサポートしています。
    (なるべく短い文字列にマッチさせようとするものぐさマッチと最長マッチを両
立させるルールはまだ誰も作れていないようです。)

(a)と(b)の特徴により、いままでhmjreの正規表現は本質的に(3)のルール
(選択パターンを使ったときに"|"の左と右で優先順位がないという特徴がありますが)で
あると思っていたのですがhttp://www.maruo.co.jp/hidesoft/2/x32187_.html#32187
に対する回答を読む限り、右側のパターンを優先させるケースがあるようなので(3)
でもないようです。
hmjreの正規表現を解釈するルールは、どのような仕様になっているのでしょうか?

[ ]
RE:07864 hmjre.dllの正規表現の基本ルーNo.07865
秀まるお さん 13/04/17 14:36
 
 お返事ですが…

 正規表現的にどうにでも解釈出来る物については、基本的に不定というか、内
部的な都合(主に速度向上)を優先してどういう結果になるかは分からないって
ことになります。例えば

    (.*)(.*)

 みたいな正規表現は、\1と\2がどうなるかの保証は無いです。そういうつもり
で作ってしまいました。

> で、hmjreの正規表現はこの三つのどれにも当てはまらないようなのです。

 全部独自に作って、それなりに高速になるように例外ロジックが多々入れてあ
るので、他のライブラリとはヒットするクセが違うのかなぁと思います。

 ただ、正規表現のルールとして、「.*」は可能な限り長い文字列にヒットし、
「.*?」は可能な限り短くヒットするってのがありますので、そういう意味では、

> http://www.maruo.co.jp/hidesoft/2/x32187_.html#32187
> に対する回答を読む限り、

 これについては、実は

    ((A.)+).*?$

 って正規表現パターンでうまく動いてくれないとおかしい気がしました。

 なんとなくバグのような気がしつつも、調べるのに骨が折れるので別のやり方
でお返事してしまった所です。

 一回調べてみます。

[ ]
RE:07865 hmjre.dllの正規表現の基本ルーNo.07866
秀まるお さん 13/04/17 17:36
 
>     ((A.)+).*?$
>
>  って正規表現パターンでうまく動いてくれないとおかしい気がしました。

 こちらの件は、すみませんがバグでした。修正させていただきます。

 それと、

    ((A.)+).*

 で検索した時に"((A.)+)"が最大にならずに".*"の方が最大にヒットしてしま
う件は、やはり高速化のためのややこしい処理があって、それのせいみたいです。
やはりそのまま仕様とさせていただきます。

[ ]
RE:07866 hmjre.dllの正規表現の基本ルーNo.07867
秀まるお さん 13/04/18 10:25
 
>  で検索した時に"((A.)+)"が最大にならずに".*"の方が最大にヒットしてしま
> う件は、やはり高速化のためのややこしい処理があって、それのせいみたいです。
> やはりそのまま仕様とさせていただきます。

 次のHmJre.dll(Version 3.51)に、(?#safemode)って構文を追加することに
します。safemodeが指定されたら内部的にやってる高速化の処理をやめます。

 例えば、

 ((A.)+)(.*)

 とかの場合だと、

 (?#safemode)((A.)+)(.*)

 と書けば、標準的な正規表現ライブラリと同じように、

 \1 が最大にヒットして、
 \2 は最小

 って動作になります。

 バグの可能性がある場合にテストするのにも有効かなぁと思うので、追加させ
ていただきます。

[ ]
RE:07867 hmjre.dllの正規表現の基本ルーNo.07869
colder さん 13/04/18 13:22
 
colderです。
>    (.*)(.*)
>
> みたいな正規表現は、\1と\2がどうなるかの保証は無いです。そういうつもり
>で作ってしまいました。
これは正規表現"a+([ab]b)+"で文字列"aaabbb"を検索したとき、5文字にマッチする
か、6文字にマッチするかはhmjreでは決められていないということになるのでしょう
か?

[ ]
RE:07869 hmjre.dllの正規表現の基本ルーNo.07870
秀まるお さん 13/04/18 13:37
 
 すみません。本題の方を理解してませんでした。全体の長さの問題もあるとは
認識してませんでした。

 で、今回のその、"a+([ab]b)+"が"aaabbb"の5文字にしかマッチしないのは、
自分としては、

> (1) とにかく一番長い文字列にマッチ

 のつもりで作っているつもりでした。なので、自分的には6文字にヒットして
くれないとダメな気がします。

 次のバージョンの(#?safemode)を付けてもやはり5文字にしかヒットしないよ
うです。また調べてお返事させていただきます。

[ ]
RE:07870 hmjre.dllの正規表現の基本ルーNo.07874
秀まるお さん 13/04/18 15:32
 
 事情を説明させていただきますと、今回の5文字ヒットの結果になるのは、こ
れも高速化のための処理が関係してまして、その高速化の処理を外してしまえば
6文字を返すようにすることが出来ます。

 ただ、それをやってしまうと、もう本当に、繰り返しパターンでのマッチング
についてはすべての可能性を探るような処理になってしまって、ちょっとややこ
しいパターンを指定するとすぐにハングアップする可能性が出てきてしまいます。

 とりあえず、safemode指定した時に「本当に一切の高速化の処理をやめるモー
ド」ってことにするとしたら、HmJre.dllの中にかなり手を入れないといけなく
て、レベルダウンが起きたら怖いかなぁというのがあります。今月中に秀丸エデ
ィタ/秀丸メール両方とも正式版にしたい所なので、とりあえず今回追加する
(?#safemode)の指定ではそこまでしないでおいて、5月以降に、もっと完璧な
safemodeをサポートするってことで対応したい所です。

 ということでお願いします。

[ ]
RE:07874 hmjre.dllの正規表現の基本ルーNo.07878
colder さん 13/04/20 14:22
 
colderです
hmjreの正規表現は一番長い文字列にマッチすると言うことですが、
ものぐさマッチになっている部分の長さはどのように処理されるのでしょうか?
"aa"は見た目、明らかに"a"よりも長いですが、正規表現"a+?"は"aa"の2文字ではな
く、"a"の1文字にマッチします。
このような単純な例だと直感的に明らかですが、正規表現が複雑な場合、どのような
ルールで長さを判定しているのですか?

[ ]
RE:07878 hmjre.dllの正規表現の基本ルーNo.07879
秀まるお さん 13/04/21 10:14
 
 ものぐさ検索と普通の検索の処理の違いですが…

 例えば(pattern1)*(pattern2)のようなケースでは、

 pattern1に0回ヒットしてpattern2にヒットするかどうか
 …ヒットしたら、ものぐさ検索の場合はそのまま検索終了。
 …普通の検索の場合は、さらに、

 pattern1に1回ヒットしてpattern2にヒットするかどうか

 を調べて、ヒットしたら、さらにpattern1に2回ヒットして…みたいなのをヒ
ットする限り繰り返すってのがノーマルな動作です。

 ところが、「a*」とか「.*」とか、ある程度単純なパターンの場合は独自の高
速化処理が働きしまして、上記の方式(0回ヒットから順にヒットする回数を増
やしてトライする方式)とは逆に、まずは「(pattern1)*」の部分が最大どこま
でヒットするかテストします。それで一番最大にヒットしたら所からpattern2が
ヒットする所まで戻っていくような処理をしています。

 戻っていく処理の中で、1つでもヒットしたらそこで検索を終了します。

 そういう、独自にやってる高速化のせいで今回おかしなことが出てきます。

 ですが、実はこの独自の高速化は絶大な速度アップ効果がありまして、これを
今さらやめるのは、ちょっといやです。なので、やはり(?#safemode)を指定した
ら、独自の高速化をやめるって風にしたい所です。

 実は手元のバージョンではちゃんと直したんですが、またこれを添付してしま
うとβテストが長引いてしまうかなぁというのがありまして、とりあえず今回は
やめとこうかなぁと思った所ですけども…。ソースコードを十分見直して添付す
るかもしれません。ちょっと考えます。

[ ]
RE:07879 hmjre.dllの正規表現の基本ルーNo.07880
colder さん 13/04/21 14:17
 
colderです
> ものぐさ検索と普通の検索の処理の違いですが…
>
> 例えば(pattern1)*(pattern2)のようなケースでは、
>
> pattern1に0回ヒットしてpattern2にヒットするかどうか
> …ヒットしたら、ものぐさ検索の場合はそのまま検索終了。
> …普通の検索の場合は、さらに、
>
> pattern1に1回ヒットしてpattern2にヒットするかどうか
>
> を調べて、ヒットしたら、さらにpattern1に2回ヒットして…みたいなのをヒ
>ットする限り繰り返すってのがノーマルな動作です。
この検索方法だとものぐさマッチが出現した部分で区切られたパターン単位で左側の
正規表現をできる限り長くするような限定的な
(3) 左側の正規表現ができる限り長く文字列にマッチするようにマッチ
のルールある事となり、最長の文字列を見つけられないケースがありませんか?
たとえば 正規表現"(a)([bcd]+?)([cfe]+)([de]+?)(f)"で
文字列"abcdeeefecdf"を検索した場合
現在は \1:a, \2:b, \3:c, \4:deee, \5:fの8文字にマッチしますが、
最長になるケースは\1:a, \2:bcd, \3:eeefec, \4:d, \5:fの12文字です。

[ ]
RE:07880 hmjre.dllの正規表現の基本ルーNo.07882
colder さん 13/04/21 20:02
 
colderです
>この検索方法だとものぐさマッチが出現した部分で区切られたパターン単位で左側
>の正規表現をできる限り長くするような限定的な
>(3) 左側の正規表現ができる限り長く文字列にマッチするようにマッチ
>のルールある事となり
これではないですね。
左側のものぐさマッチをできる限り短くするというルールが一番長い文字列にマッチ
するというルールより優先的に適応されると考えればいいでしょうか。

[ ]
RE:07882 hmjre.dllの正規表現の基本ルーNo.07888
秀まるお さん 13/04/22 11:21
 
 とりあえずですが、「最大の長さにヒットすべきなのに最大じゃない所にヒッ
トしてしまうことがある」の点については、一応バグと言われたらバグな訳です
けども、これを、速度を犠牲にして直してしまうと、今度は逆に「こういう正規
表現パターンで以前はちゃんと実用的に動いていたのにバージョンアップしたら
ハングアップするくら遅くなった」と言われてしまう可能性がありますので、こ
れについてはすみませんが現状そのままにしつつ、

   (?#safemode)

 を付けたら、速度を犠牲にしてでもちゃんと最長一致で結果を返すって仕様に
させていただきます。

> 左側のものぐさマッチをできる限り短くするというルールが一番長い文字列にマッチ
> するというルールより優先的に適応されると考えればいいでしょうか。

 ルールがどうかっていう話であれば、ものぐさ検索の定義としては、「ヒット
する長さが何通りもある場合、一番短い長さにヒットする方を優先する」ってこ
とじゃないかと思うし、それは別にHmJre.dllだからどうこうって話とは別問題
で、世の中でそういう風に定義されてるって話だと思います。

 (質問されてる意味をよく分かってない気もします)

 正規表現のルールとしては、特に僕自身は「左側にある方が優先」という風に
は思ってないです。内部的な処理の順序の都合でどうしても左側を先に処理する
ことがほとんどなので、あいまいな正規表現パターンを指定した場合は結果的に
左側が優先されたような結果になることが多いかとは思います。

 例えば、

   ^(.*)(.*)$

 とか

   ^(.*?)(.*?)$

 みたいに書いた時に、\1と\2がどうなるか、それについては内部の処理の都合
で決まるので、どうなるかの保証は無いですってしか言えないです。

[ ]
RE:07888 hmjre.dllの正規表現の基本ルーNo.07889
colder さん 13/04/22 15:04
 
colderです
> ルールがどうかっていう話であれば、ものぐさ検索の定義としては、「ヒット
>する長さが何通りもある場合、一番短い長さにヒットする方を優先する」ってこ
>とじゃないかと思うし、それは別にHmJre.dllだからどうこうって話とは別問題
>で、世の中でそういう風に定義されてるって話だと思います。
>
> (質問されてる意味をよく分かってない気もします)

一番長い文字列にマッチするというルールのもとで、ものぐさマッチをサポートして
いるのがhmjre.dllだけなので、
局所的に短い文字列にマッチさせようとするものぐさマッチと一番長い文字列にマッ
チさせようとするルールの折り合いをどのように付けているか聞きたかったのですか。
世の中一般で定義されているのは左側優先ルールのもとでのものなのでhmjre.dllに
は適用できないです。

どのようなルールでマッチする文字列が決まるかを把握しておくことは
正規表現を使った検索をする上で、誤マッチを避け、速い正規表現を書くために重要
です。
今回の一連の回答でだいたいは理解しましたが。

[ ]
RE:07888 hmjre.dllの正規表現の基本ルーNo.07892
秀まるお さん 13/04/22 15:56
 
 (?#safemode)の修正をして、とりあえず今回の件はうまくいくようになったん
ですが、まだいろいろテストしてたらダメなパターンがありました。

    (a.?)+

 って正規表現パターンが

    aax

 って文字列の3文字にヒットせず、2文字にヒットしてしまいます。

 実は、BRegExp.dllや鬼車(bregoni.dll)でもHmJre.dllと同様に2文字にヒ
ットしてしまいます。しかし、BRegExp.dll等では、

    (a.?)+$

 とすれば3文字にヒットします。HmJre.dllでは$付きだとヒットしなくなって
しまうという、もっと悪い結果になります。

 ですが、bregoni.dllだと「aaaaaa…aaaabcd」って極端に長い文字列を書いて
「(a.?)+$」で正規表現検索すると、ハングアップしたのごとく遅くなります。
たぶん「(a.?)」の場合はHmJre.dllと同様のロジックでやってて、「(a.?)+$」
の場合は高速化の効かない厳密な総当たりロジックでやるような判定をしてるの
かと思います。

 根本的に、こういうややこしい正規表現パターンでうまく最長文字列にヒット
させるのは大変難しいです。

 直せるかどうか自信が無いですが、とりあえず(?#safemode)の場合は厳密な結
果を返せるようにトライしてみます。

[ ]
RE:07892 hmjre.dllの正規表現の基本ルーNo.07893
colder さん 13/04/22 17:32
 
colderです
>    (a.?)+
>
> って正規表現パターンが
>
>    aax
>
> って文字列の3文字にヒットせず、2文字にヒットしてしまいます。
>
> 実は、BRegExp.dllや鬼車(bregoni.dll)でもHmJre.dllと同様に2文字にヒ
>ットしてしまいます。しかし、BRegExp.dll等では、

これはBRegExp.dllや鬼車が採用している左側を優先させるルールでは正しい結果です。
左側優先ルールの下では一回目のa.?のマッチでaaにマッチさせたら、
+による一回以上という条件を満たしているので、その後に別の正規表現が続かない
限り、2回目のマッチを成功させるために一回目にマッチさせた2文字のaを手放すこ
とはないです。
jre32.dllなどが採用している最長の文字列にマッチさせるルールでは3文字にマッチ
しますけれど。
>  ですが、bregoni.dllだと「aaaaaa…aaaabcd」って極端に長い文字列を書いて
> 「(a.?)+$」で正規表現検索すると、ハングアップしたのごとく遅くなります。
BRegExp.dllや鬼車で正規表現を書き慣れた人だとこのような正規表現を書かず、実
質的な同等な、(a[^a\n]?)+$みたいに書くかなぁと思います。

[ ]
RE:07893 hmjre.dllの正規表現の基本ルーNo.07895
秀まるお さん 13/04/22 19:43
 
 いろいろテストしてたらまた別のバグを見つけてしまいました。

 (|a)+x

 が、「x」にヒットしませんでした。これまた修正させていただきます。これ
はまた別の問題(長さ0の繰り返しヒットは無限ループの可能性があるというこ
とでヒットしない扱いにしてた)でした。

 他にもいろいろテストしするとボロが出そうで怖いですけど、とりあえずヒッ
トする長さの問題は別にして、ちゃんとヒットすべきものにヒットしないのはま
ずいので、そっちの問題から先に対応を考えさせていただきます。

[ ]
RE:07895 hmjre.dllの正規表現の基本ルーNo.07898
秀まるお さん 13/04/24 18:59
 
 先ほど秀丸メールのV6.10β46をアップロードしたんですが、これに今回の一
連の修正版HmJre.dll(Version 3.52)を添付しました。

 (?#safemode)を付けた場合だけ、正確な「最長一致」の正規表現マッチングを
するようにしました。

 最初はとにかく「総当たり作戦」でやってみたんですが、それだとあまりにも
遅くて使い物にならず、一応、safemodeの場合でもそれなりの高速化の処理はし
ています。なので、もしかしてその辺の処理がバグってたら、やはりヒットすべ
き所にヒットしないケースが出てきてしまうかもしれません。一応いろんなパ
ターンでテストしたのでそう簡単にはバグケースは出てこないんじゃないかと思
います。

 いろいろ工夫したおかげで (a.?)+$ を「aaaaaaa...」の長い文字列にマッチ
ングさせる時とか、鬼車さんよりは高速動作するようになりました。(他のパ
ターンでは逆に遅いこともあるかもしれませんが)

 ということでよろしくお願いします。

 こちらで動作確認したパターンを一応書きます。
 (「…」は非常に長いって意味)

(?#safemode)(a.?)+(ab|bc)+
aabc

(?#safemode)a+(a|aabb)
aaabb

(?#safemode)(a+)(ab|[b-c][d-e][f-g])+
aaaaaaaaaaaaaaaaaaaa…aaaaaabdf

(?#safemode)a+([ab]b)+
aaabbb


(?#safemode)(a.?){3,4}   --> aが8文字から3文字にヒット。
aaaaaaaaa

(?#safemode)(a.)+
aaaaaaaaa

(?#safemode)(a.?)+
aaaaaxaxaxaaaaax


■速度が問題。
(?#safemode)(a.?)+xxx$
(?#safemode)(a.?)+(xxx|yyy)+$

aaaaaaaaaaa…aaaaaaaaaxxx
aaaaaaaaaaa…aaaaaaaaaxxxyyy
aaaaaaaaaaa…aaaaaaaaaxxxyyyxxxyyy
aaaaaaaaaaa…aaaaaaaaaxxxyyyxxxyyyz

(?#safemode)(|a){10,100}xxx

aaaaaaaa…aaaaaaaaxxxy

(?#safemode)(ac|a|(?=b)){10}b
(?#safemode)((?=b))+b

ab
aaaaaaaacaaaaa
bbb

[ ]
RE:07898 hmjre.dllの正規表現の基本ルーNo.07899
アルビレオ さん 13/04/24 23:15
 
ユーザーのアルビレオです。

若干話が噛み合っていないなと思いながらも、議論する人数が増えるとさらに混
乱しそうなので控えていました。
ツリーの流れ上ここにぶら下げますが、秀まるおさん向けというより colder さ
んやここを見ている方向けの書き込みです。

個人的に試してみたくなったケースの結果を以下に書いておきます。
対象文字列はどちらも 'aaaaaaaa'(aが8個) です。

○ケース1
検索パターン: (aa)+(aaa)+

これは左側の部分パターンが最長になることを優先すると (2+2)+(3) の7文字に、
パターン全体の長さが最長になるようにすると (2)+(3+3) の8文字に一致するよ
うになっています。

結果:
 safemodeなし:先頭7文字にマッチ
 safemodeあり:8文字全体にマッチ

となり、safemodeでは全体の長さを優先することが確認できました。

○ケース2
検索パターン: (a+)(a+)(a+)
置換文字列: \1□\2□\3

最長一致指定が複数並んでいた場合、矛盾なく一致する部分パターンの長さの取
り方が何通りもあるケースです。

結果:
 safemodeなし:aaaaaa□a□a
 safemodeあり:a□a□aaaaaa

このパターンでは通常モードでは左側が最長に、safemodeでは右側が最長になり
ました。
ただしあくまで速度を優先ということなので、検索パターンによってどの繰り返
しが最長になるかは変化する可能性があります。
なので「safemodeだと右側を優先的に最長にする」などとは考えない方がいいと
思います。

[ ]
RE:07899 hmjre.dllの正規表現の基本ルーNo.07900
秀まるお さん 13/04/25 00:41
 
 テストどうもです。

> このパターンでは通常モードでは左側が最長に、safemodeでは右側が最長になり
> ました。

 検索ロジックがまったく別なので、特に意識はしてまんせでしたが、タグのヒ
ットのされかたもまったく別になってしまうようです。たまたまですけど。

 それよりも、今さらながら、ものぐさ検索のテストを全然してないことに気づ
いて、テストしてみたら、やっぱりダメでした。

 (?#safemode)a+? が aaaaa の複数文字にヒットしてしまいました。やっぱり
すんなりとはいかない物のようです。また修正させていただきます。

[ ]
RE:07900 hmjre.dllの正規表現の基本ルーNo.07901
アルビレオ さん 13/04/25 02:47
 
アルビレオです。

> それよりも、今さらながら、ものぐさ検索のテストを全然してないことに気づ
>いて、テストしてみたら、やっぱりダメでした。
>
> (?#safemode)a+? が aaaaa の複数文字にヒットしてしまいました。やっぱり
>すんなりとはいかない物のようです。また修正させていただきます。

言われてみるとこれはなんとなく想像がつきますね。
おそらく
 1.パターン全体に一致する最長のものを探し
 2.各部分一致に対応付けして余りが出ない組み合わせを見つける
という手順だとそうなりそうです。

この件で考えていたときに気づいたのですが、最長一致の繰り返し指定 ? * +
{} を含んでいないパターンでものぐさ検索 +? を使っている場合、これは必ず
「一回だけの繰り返し」と同じ意味になります。({}の固定回数の繰り返しは最
長一致ではないので除外)
そして最長一致指定を含んでいない場合にありうるのは「固定長文字列のみ」
「ものぐさ検索のみ」「固定長とものぐさ検索」しかないということで、結果的
に検索パターン全体が固定長文字列の検索とみなせるので最長の文字列を探す必
要はありません。
別の言い方をすると上記の1が必要なのは最長一致繰り返し記号を含んでいる場
合だけで、含んでいなければ1をスキップしても結果はまったく同じになります。

というわけで、最長一致指定の有無の判定を入れておけば a+? の結果が正しく
なる上に、処理の一部をスキップできるので高速化されて一石二鳥ではないでし
ょうか。

[ ]
RE:07901 hmjre.dllの正規表現の基本ルーNo.07902
秀まるお さん 13/04/25 15:13
 
 safemodeなものぐさ検索は、また別ロジックで作らないとダメでして、それは
それで今トライしてる所ですが、テストしてたらまたダメなパターンを見つけて
しまいました。


   (?#safemode)(aaa(?=bbb)|aa(?=abbb))+ab

 が、   aaabbbb

 にヒットしませんでした。これも修正します。

[ ]
RE:07902 hmjre.dllの正規表現の基本ルーNo.07903
秀まるお さん 13/04/25 17:44
 
 ついでに、既存のダメパターンの報告です。safemodeではうまくヒットするよ
うにします。

・ 「(a|aa)+?a」が「aaa」のうちの2文字にヒットせずに3文字にヒット
  してしまう。

[ ]
RE:07903 hmjre.dllの正規表現の基本ルーNo.07904
アルビレオ さん 13/04/25 22:03
 
アルビレオです。

| が絡むとややこしそうだとは思ってましたが、大変そうですね。
文法としては +? はあくまで繰り返し回数が最小になるようにするだけで、()内
の最短のものを選ぶって意味ではないという仕様の方が自然な気がしますが、検
索パターンを書く側からすれば最短のものを選んで欲しいでしょうし。

雑談失礼しました。

[ ]
RE:07904 hmjre.dllの正規表現の基本ルーNo.07905
秀まるお さん 13/04/26 00:12
 
> 文法としては +? はあくまで繰り返し回数が最小になるようにするだけで、()内
> の最短のものを選ぶって意味ではないという仕様の方が自然な気がしますが、検
> 索パターンを書く側からすれば最短のものを選んで欲しいでしょうし。

 とりあえず手元のバージョンでは、「繰り返し回数が最小になる」を優先しつ
つ、同じ繰り返し回数の中でヒットする箇所が複数ある場合は最小長さを優先す
るようにしてしまいました。

 ただ、アルビレオさんのおっしゃる通り、「()内の最短のものを選ぶって意味
じゃない」ってことは正しいような気がするので、そうだとすると、ややこしく
なります。

 例えば

    (?#safemode)(a|aa)+

 が「aa」にヒットする時は2文字で間違い無いですが、

    (?#safemode)(a|aa)+?

 は、(a|aa)の方が長い方にヒットする優先なら、aaにヒットしないといけない
ことになりそうです。

 ちょっと困りました。

 鬼車さんの場合は、基本左側優先なので、

    (?#safemode)(a|aa)+?   なら1文字ヒット優先、
    (?#safemode)(aa|a)+?   なら2文字ヒット優先

 となるようです。

 処理の都合的には「繰り返し回数最小の中で、さらに最小長さ優先」が作りや
すいですけども。

 何かご意見ありましたらお願いします。

[ ]
RE:07905 hmjre.dllの正規表現の基本ルーNo.07906
秀まるお さん 13/04/26 00:55
 
 やっぱりアルビレオさんのおっしゃる通り、ものぐさじゃない部分については
基本長い方にマッチするのが優先でないとまずい気がしてきました。

 というか、最終的にヒットする文字列として、なるべく長い物にヒットするの
が基本なので、あくまで「+?」の部分の繰り返し回数的には最小の物を優先しつ
つ、全体として一番長いのを返すって仕様にすべきかと思います。

 例を1つ考えてみました。

正規表現パターンの例: (?#safemode)(a|ay)+?(yy|yyyxxx)

ヒットする文字列の例: ayyyxxx

 (a|ay)が最大にヒットするのが優先だとすると、「ay」がヒットするんですが、
そうしてしまうと後ろの部分が「yy」にしかヒットせず、全体して4文字にヒッ
トする形になります。

 「最終的に返すのが最大」って仕様にすべきかと思うので、それを考慮した結
果、「a|ay」の部分はaがヒットして、後ろの部分はyyyxxxがヒットすると、結
果として最大が返るということで、そうなるようにしてみます。

 っと考えていくと、もっとややこしいケースもあって、最終的に「最大長さを
返す」って仕様を完璧に実装出来ないケースもあったりするかもしれない気がし
てきました。

 で、最初のcolderさんの話に戻ると…

> (1)はAWKなどで使われているルールで、基本的に後方参照をサポートしていません。
> (少なくとも、私の知る限り、後方参照をサポートしているツールはありません。)

 ここで言われてる後方参照とは

   (?=xxxx)
   (?!xxxx)

 の、いわゆる後方一致/後方不一致指定のことかと思うんですが、たしかにこ
れがからんでくると、完璧に「最大長さを返す」ってことが実現不可能なケース
があるのかもしれません。

 僕には具体的な例が思いつかないですけども…。

 奥が深いです。

[ ]
RE:07906 hmjre.dllの正規表現の基本ルーNo.07907
colder さん 13/04/26 14:19
 
colderです

>> (1)はAWKなどで使われているルールで、基本的に後方参照をサポートしていません。
>> (少なくとも、私の知る限り、後方参照をサポートしているツールはありません。)
>
> ここで言われてる後方参照とは
>
>   (?=xxxx)
>   (?!xxxx)
>
> の、いわゆる後方一致/後方不一致指定のことかと思うんですが、
これは\1,\2のことです。

> というか、最終的にヒットする文字列として、なるべく長い物にヒットするの
>が基本なので、あくまで「+?」の部分の繰り返し回数的には最小の物を優先しつ
>つ、全体として一番長いのを返すって仕様にすべきかと思います。
なるべく長いものにヒットさせるのと、ものぐさマッチとを両立させるのは可能なん
だろうかというのが、そもそもの疑問なんですが。
たとえば(pattern1|pattern2)でpattern1には通常の繰り返し指定が含まれていて、p
attern2にはものぐさマッチが含まれている場合で、
pattern1の正規表現のマッチに成功させた文字列より、
pattern2の正規表現をより短い文字列にマッチさせることができなかった場合、
単に、pattern2の正規表現にマッチした文字列の方が長いと言うだけで、pattern1の
正規表現にマッチした文字列より、よりよいマッチといえるのか分からないです。
逆にpattern2にマッチした文字列の方が短い場合でも、pattern2は長い文字列にマッ
チさせることを目指していないし、短いというだけでpattern1の正規表現よりよくな
いマッチといえない気がします。
さらに両方にものぐさマッチが含まれている場合、両者とも短い文字列にマッチさせ
ようとして、両者を比較してより短い文字列にマッチさせられなかった方がよりよい
結果というのはさらに理解しがたいです。



[ ]
RE:07907 hmjre.dllの正規表現の基本ルーNo.07908
秀まるお さん 13/04/26 15:16
 
 たしかにものぐさ検索と現状の「最大長さを返す」は矛盾してるような気がし
ますが、一番矛盾しそうなのは、まさにその、

  (pattern1|pattern2)

 と組み合わせて使った場合になるかなぁと思います。この場合、HmJre.dllで
はpattern1とpattern2のどちらか長くヒットする方を優先してしまうので、もの
ぐさ検索と組み合わせて指定したら期待した結果が得られない可能性が高い気は
します。

 しいて、(...|...)でも最小長さにヒットする方優先、または鬼車さんみたい
に左側優先にする表現方法をサポートしたらいいのかもしれませんけど、「|」
での優先順位を指定するような構文て、他の正規表現ライブラリには無さそうで
す。

 (?#shortpriority) とか、 (?#leftpriority) とかで指定するとかがあったら
いいかもしれませんけど…。

 とりあえず、現状で具体的に困るってケースが出てる訳じゃなさそうなので、
それでよしとさせていただきつつ、何か困る事例があるなら、(...|...)での優
先順位を指定する構文を独自に追加するなりって対応を考えるって方向でどうで
しょうか。

 あるいは、他の点でもご希望があれば、可能な限り対応したいと思います。
 (互換性が壊れてしまうのは別として)

[ ]
RE:07907 hmjre.dllの正規表現の基本ルーNo.07909
アルビレオ さん 13/04/26 16:56
 
アルビレオです。

>なるべく長いものにヒットさせるのと、ものぐさマッチとを両立させるのは可能なん
>だろうかというのが、そもそもの疑問なんですが。
>たとえば(pattern1|pattern2)でpattern1には通常の繰り返し指定が含まれていて、p
>attern2にはものぐさマッチが含まれている場合で、
>pattern1の正規表現のマッチに成功させた文字列より、
>pattern2の正規表現をより短い文字列にマッチさせることができなかった場合、
>単に、pattern2の正規表現にマッチした文字列の方が長いと言うだけで、pattern1の
>正規表現にマッチした文字列より、よりよいマッチといえるのか分からないです。

これは割と単純な話ですよ。
ものぐさマッチ記号 +? はあくまで「直前の1文字または1グループが最短になる
ようにする」という意味であり、それ以外には影響しません。
だから上の例でいえば pattern1 と pattern2 の両方がものぐさマッチのみのパ
ターンだとしても (pattern1|pattern2)でどちらを選ぶかはものぐさマッチの外
の世界の話なので無関係、つまり最長のものが選ばれます。
もしも短い方にマッチして欲しいなら (pattern1|pattern2)+? って書けばいい
のかな?(自信なし)

ものぐさマッチは「最短となる検索結果」にマッチするのではなく「最短となる
繰り返し」にマッチすると定義されているのが肝になります。(自分で言ってて
わかりにくいですが)

[ ]
RE:07909 hmjre.dllの正規表現の基本ルーNo.07910
秀まるお さん 13/04/26 19:36
 
> ものぐさマッチ記号 +? はあくまで「直前の1文字または1グループが最短になる
> ようにする」という意味であり、それ以外には影響しません。

 ものぐさ検索はこうだっていうちゃんとした定義がどこかにあるのならいいん
ですが、実際は各正規表現ライブラリ毎に好きなように実装してたりするのかも
しれません。そういう自分自身こそ、この辺の定義がよく分かって無いで作って
たりするので怖いです。今回の話でやっと仕様がはっきりしましたけども。

 鬼車さんが、(|a)を0文字にヒットする方優先するとか、その辺も知らなかっ
たし…。colderさんはなぜにこんなに詳しいのか…。いろいろバグも見つけても
らってるし、その他いろいろ教えてもらってばかりです。

[ ]
RE:07909 hmjre.dllの正規表現の基本ルーNo.07911
colder さん 13/04/26 20:25
 
colderです。

>ものぐさマッチ記号 +? はあくまで「直前の1文字または1グループが最短になる
>ようにする」という意味であり、それ以外には影響しません。
>だから上の例でいえば pattern1 と pattern2 の両方がものぐさマッチのみのパ
>ターンだとしても (pattern1|pattern2)でどちらを選ぶかはものぐさマッチの外
>の世界の話なので無関係、つまり最長のものが選ばれます。
アルビレオさん。
patternの選択で内部にものぐさマッチがあろうがなかろうが長い方が選ばれるのは
いくつかのパターンを試せば分かるし、そういう仕様なんだということも理屈では分
かるのですが、その仕様が妥当かどうかいう点で違和感があるというだけのごく個人
的な問題です。
最長マッチというルールのもとでものぐさマッチがあるのはhmjre.dlだけなので、こ
のあたりの仕様も秀まる夫さんの胸三寸で決めればいいし、それがこちらの感覚と違
っているというしょうもない話です。

>もしも短い方にマッチして欲しいなら (pattern1|pattern2)+? って書けばいい
>のかな?(自信なし)
これは全く意味が異なります。
hmjre.dllで選択の短い方にマッチさせる方法はないはずです。

[ ]
RE:07911 hmjre.dllの正規表現の基本ルーNo.07912
アルビレオ さん 13/04/26 21:50
 
アルビレオです。

>最長マッチというルールのもとでものぐさマッチがあるのはhmjre.dlだけなので、

ここが一番ひっかかっていた点なので確認したいのですが、

○(...)+? のパターンが単独で使用された場合、n回の繰り返しで最短のものは
常に1回なので +? をつけてもつけなくても同じ結果になる

○ * や + は最長の繰り返しにマッチする

というのは(その機能がサポートされていれば)どのような実装でも共通ですよ
ね?

そうなるとものぐさマッチが実質的に意味を持つのは * や + のような最長一致
指定(可変長)と共に使われている場合のみで、* や + を含んだパターンであれ
ば +? を含んでいても検索パターン全体としては最長一致になるのではないでし
ょうか?
話がややこしくなるので | のことはひとまず置いておいて、そうならない例が
あるのかどうかを教えていただけないでしょうか。

[ ]
RE:07899 hmjre.dllの正規表現の基本ルーNo.07913
秀まるお さん 13/04/26 23:28
 
 今さらですが、タグ付き正規表現でのテストをしてないことに気づいて今から
見直したら、しいて「左側が最長」ってルールが無いにしても、おかしいケース
がありました。

 また直します。

ダメだった例:

(?#safemode)(a+)(a+?)  で、  "aaa"にヒットして、「\1,\2」に置換する時に、

  aa,a   にならないとおかしいはずが、a,aaになってしまう。

[ ]
RE:07912 hmjre.dllの正規表現の基本ルーNo.07914
秀まるお さん 13/04/26 23:35
 
> 話がややこしくなるので | のことはひとまず置いておいて、そうならない例が
> あるのかどうかを教えていただけないでしょうか。

 | と繰り返し以外ってことになると、特に「複数にヒットする可能性がある
物」って物は他に無いので、他には例は無いような…。(って僕がお答えする話
でもないですが)

 ちなみに鬼車さんには

 (...)+
 (...)+?

 の他に、

 (...)++

 っいう、「強欲」って指定もあるようです。

http://www.geocities.jp/kosako3/oniguruma/doc/RE.ja.txt

 知りませんでした。

[ ]
RE:07914 hmjre.dllの正規表現の基本ルーNo.07915
秀まるお さん 13/04/27 21:43
 
 いろいろテストしたらまだダメなパターンがありました。

(?#safemode)^(a|aa)?(aa)$

 が、「aaa」にヒットしませんでした。「?」もsafemode時には新ロジックに変
更します。

[ ]
RE:07915 hmjre.dllの正規表現の基本ルーNo.07918
秀まるお さん 13/04/28 15:46
 
 またしてもダメパターンを見つけてしまいましたが、これについてはとりあえ
ず仕様で逃げようと思います。

    (?#safemode)^(a??)+$

 が、任意の「a」だけの行にヒットしないです。鬼車さんはちゃんとヒットし
ました。

 ものぐさじゃない繰り返しパターンの中にものぐさ指定があるのは基本的にダ
メみたいです。対応するとしたら、繰り返しパターンの中にあるものぐさ指定は
ものぐさじゃない扱いに変換して検索させるしか無いと思います。(HmJre.dll
の現状のロジックだと)

[ ]
RE:07918 hmjre.dllの正規表現の基本ルーNo.07919
秀まるお さん 13/04/30 00:40
 
 先ほどアップロードした秀丸メールV6.10正式版に、HmJre.dllのV3.53を入れ
てしまいました。一応、(?#safemode)を付けない限りはレベルダウンは無いはず
ということで、いきなり正式版に入れてしまいました。

 いろいろ改良してたらsafemodeでもそんな極端には遅くならなくなったので、
秀丸エディタのV8.30正式版が出た後のV8.40βのタイミングで、現状のsafemode
相当を標準動作にしてしまおうと思います。

[ ]