コードを埋め込んだ全知全能の正規表現

11の倍数を発見する正規表現というのは書けるだろうか。
そんなもんいるのかというのは置いておいて、
作れるかどうかでいうと、Perlでは案外簡単に作れてしまいます。
えらいもんですね。


まずパターン中にコードを埋め込めるんですね。

m/(?{print "X"})/

何のことかわからないが、とにかく(?{~})の中は実行されると言うこと。
これを使ってやります。といってもこれだけでは駄目なんですが。
これとこういうパターンを使います。
(?(条件)真の時|偽の時)という風なパターンがあるんですね。
条件は(?{~})を使ってコードで書けると。
それともう1つ使えばできます。それは(?!~)ってパターンです。
これは~の文字列を含まない文字列というパターン。
実は含まない文字列のパターンってむちゃくちゃめんどくさいんですよ。
けどこれを使えば簡単なんですね。(?:(?!foo).)+とかするだけです。
これの~部分に何も入れない(?!)ってパターンは何にもマッチしないという意味らしい。
これらを使って(?(?{$1%11==0})|(?!))っていうのを$1をキャプチャするところの直後に入れると、
$1%11==0を満たさないとき(?!)ってパターンが入ってドボン。
という仕掛けになってるわけだ。
というわけでこれを使って11の倍数を検索してみた。

print join(',' , '22597619494114889245'=~m/(\d+?)(?(?{$1%11==0})|(?!))/g),"\n";

すると、22 , 597619 , 94114889と出てきます。うまいこといってますね。
この程度なら極端に遅いなんて事もありません。


これの使い道ですが、例えばIPv4のIPアドレスにマッチするするパターンとかね。

m/(\d{1,3})(?(?{$1<256})|(?!))\.(\d{1,3})(?(?{$2<256})|(?!))\.(\d{1,3})(?(?{$3<256})|(?!))\.(\d{1,3})(?(?{$4<256})|(?!))/

各桁の数字は1桁から3桁だけど、3桁は3桁でも256未満ということでこういう風に条件を埋め込めると。
もちろんこの場合はガリガリ書けば256未満のパターンをこんなの使わなくても作れますけどね。
けど意味がわかりにくい。けどこれなら一目瞭然ですよね。
いや知ってればですけど。けど$1<256っていう制約があるんだなってわかりそうなもんだ。
こういう正規表現あってもいいと思ってたけど、さすがPerlやってくれますね。


Perlのマッチはかなり柔軟だと思います。
PHPでは置換でコールバック関数使うときは特別の置き換え関数を使ったけど、
Perlの場合はeオプションつけるだけですからね。
さすがだなと思いますけど、これPerl以外で通用するのか?
それだけが心配なところです。Rubyではそのまま打っても通用しなかったからね。
また調べてみることにしよう。