2015-06-28

Regex Golf をやってみた 6

Regex Golf 6回目(5回目はこちら

正規表現によるパズルゲーム? Regex Golf 5問目 "Abba" の続きです


以下、ネタバレ
前回は右側にマッチする正規表現が
(.)(.)\2\1
というところまで書きました。


後はこれを否定すれば良いのです。
特定のパターンを含まないことを検索するには否定先読み
(?!   )
が使えそうです。ということで、
(?!(.)(.)\2\1)
としてみます。


…左側はいいんですが右側は全滅しました。
正規表現にマッチした部分は下線が入るのですが、右1行目を見ると "a_bba" となっています。
何故、1文字目と2文字目の間でマッチしてるのでしょうか?
2行目は "_anallagmatic" となっています。
何故、1文字目の前でマッチしてるのでしょうか?

恐らく否定パターンにマッチしない文字列が見つかったところでマッチしてしまうからです。
2行目は最初の4文字 "anal" で否定パターンにマッチしないので1文字目の前でマッチします。
1行目は最初の4文字 "abba" では否定パターンにマッチしますが、2文字目から始まる "bba" で否定パターンにマッチしないので1文字目と2文字目の間でマッチします。

今回は文字列全体に含まれていない物をマッチさせたいため
  • 行頭から否定パターンを探す
  • 否定パターンを探す範囲は行末まで
  • 否定パターンはどのにあってもよい
ということで
  • 行頭から:^
  • 0文字以上の文字があって:.*
  • "abba" のようなあってはいけないパターンの文字列はなくて:(?!(.)(.)\2\1)
  • 0文字以上の文字がある:.*
^.*(?!(.)(.)\2\1).*$
としたくなりますがこれではダメです。
なぜなら1つめの .* が文字列全体に相当するため全ての文字列にマッチしてしまうからです。


そこでこのようにしてみます。
^(?!.*(.)(.)\2\1.*$)
否定先読みは行頭から開始し、特定パターン "(.)(.)\2\1" を含む行末までの文字列としてみます。


上手くいきました。
しかしよく考えてみると、行末までの指定は要らない気がします。
行頭から順に見ていって特定パターンが見つかった時点でダメだし、見つからなければ行末まで探すはずです。
ということで私の解答は
^(?!.*(.)(.)\2\1)
とします。


7回目に続く…

0 件のコメント: