正規表現の論理和 | についてNo.38086
fzok4234 さん 20/03/29 04:18
 
お世話になっております。

さて、正規表現のパターンの論理和についてですが、注意して取り扱わないと思わぬ
動作になってしまうことがあります。検索対象の文字列

abc

に対しての検索パターン

(a|ab)

は、「aとabとの両方にマッチ」ではなく「専らabのみにマッチ」となってしまうと
いうことです。これは、bとcとの両方にマッチさせようとして

(?#lookbehind)(?<=(a|ab))\c

としても、実際にはcにしかマッチしないことでわかります。一方、

(bc|c)

は見た目通りに「bcとcとの両方にマッチ」となるのでなおさらややこしいです。実際、

(?#lookbehind)\c(?=(bc|c))

はaとbとの両方にマッチします。

このことはヘルプのどこにも書かれていなくて、また、Web上にも情報がなくて非常
に気付きにくいです。このことも含め、正規表現の取り扱いで思わぬマッチを防ぐた
めの注意事項が他にあればヘルプに記述してもらえればありがたいです。



[ ]
RE:38086 正規表現の論理和 | についてNo.38092
秀まるお2 さん 20/03/30 09:19
 
 正規表現パターンは基本的には長い文字列の方に優先してヒットするってことだと
思いまして、実際、HmJre.dllでもなくべるそういう風にしていると思います。ただ、
これが正規表現の正式なルールなのかどうか、僕もよく分かってません。ただ他の正
規表現ライブラリ類と結果が違うのが良くないので、そういう風にしているという感
じです。

 実際に絶対に「長い方にマッチすることを保証」している訳では無いというか、た
ぶん世の中の正規表現の処理も保証までしてないので、その辺について詳しく記述し
てる例が少ないってことじゃないかと思います。

 特に前方一致/不一致とかの関係があると内部的な処理もややこしくなるので、期
待した長さの方が結果として出てこないことがあるかもしれないです。

 HmJre.dllの場合は前方一致/不一致の中で繰り返しパターンも使えるという独自の
拡張もしてるので、なおさらややこしいです。なのであんまりこの辺の仕様について
「こうなります」的なことは自分でも言いづらい所でして、自分で分かってない以上、
ヘルプに書くのも難しいです。

[ ]
RE:38092 正規表現の論理和 | についてNo.38093
fzok4234 さん 20/03/30 10:02
 
回答ありがとうございます。


あれからいろいろWebで調べたところ、この問題に触れているサイトが1件見つかりま
した。

https://techracho.bpsinc.jp/hachi8833/2018_11_30/65123

ここの内容によると、テキスト制御型エンジンでは常に最長の文字列にマッチする仕
様であり、一方の正規表現制御型エンジンでは

(abc|ab|a)

という風に長い方から短い方へと順に記述することで全てのパターンにマッチするも
のもあるとのことです。

実のところ、当方で繰り返し指定子の入れ子で動作が重くなる問題がよく発生してお
り、例えば

(\c*\s)?

という*と?の入れ子があったとき、入れ子にならない代替の記述方法として

((\y|\Y)|(\c*\s))

を試してみようと思っていました。しかし、実際にテストしたところ長さ0の文字列
(\y|\Y)にマッチせず専ら(\c*\s)のみにマッチしてしまう現象が起きたためこの問題
に気付いた次第であります。


>なのであんまりこの辺の仕様について「こうなります」的なことは自分でも言いづ
>らい所でして、自分で分かってない以上、ヘルプに書くのも難しいです。

一応、「こういう動作になります」という断言はできなくても、「動作が不定である
ため思わぬ問題を引き起こす可能性があること」自体はヘルプ上で注意喚起をはかっ
たほうがよいと思います。



[ ]
RE:38093 正規表現の論理和 | についてNo.38094
秀まるお2 さん 20/03/30 10:31
 
 とりあえず、

 「| パターンの論理和 」

 のヘルプの中に、「複数のヒット候補がある場合は長い方にマッチするのが基本動
作になります」だけ追加しようと思います。(これは間違いないので)


   ((\y|\Y)|(\c*\s))

 を最短一致優先でマッチさせるにはどうしたらいいのか・・・。

 例えば

  (a|ab|abc)

 を最短一致でマッチさせるとしたら、

    (a|ab|abc){1}?

 とすればいいようではあります。なので、

   ((\y|\Y)|(\c*\s)){1}?

 とすれば期待した動作になるかなぁと思いますけども。

[ ]
RE:38094 正規表現の論理和 | についてNo.38095
fzok4234 さん 20/03/30 10:47
 
ご教示ありがとうございます !!

検索対象

abcdef

に対して

(?#lookbehind)(?<=(a|ab|abc|abcd){1}?)\c

を実行したところ、正しく

b
c
d
e

の4個にマッチしました。

量指定子{n}の意外な役割にちょっと驚きです。


[ ]