正規表現の文字クラス表記の互換性

狭義の「正規表現」という言葉は、grepコマンドの受け付ける正規表現であり、「拡張正規表現」という言葉は、egrepの受け付ける正規表現であるというのが、伝統的な用法であろう。
で、その後awkPerlRuby等の言語が拡張正規表現をさらに拡張して、現在ではそういったものをひっくるめて漠然と「正規表現」と呼ばれている。もちろん、仕様は少しずつ違うので、「awk正規表現」、「Perl正規表現」、「Ruby正規表現」は全て異なる。


という風に思っていたのだが、これらは「egrepの拡張正規表現」に対して上位互換性が無いようだ。気づいたのは文字クラス中の特殊文字

[a\-z]

これは、grep/egrepの正規表現/拡張正規表現(以下拡張正規表現と書く)では、「a または \からz までの全ての文字」にマッチする。ところが上記各言語の「正規表現」では、「a または - または z」にマッチする。
拡張正規表現では、文字クラス指定の [ ] 内では \ は特殊文字ではないが、各言語の「正規表現」では、\- とすることで - の文字クラス内での範囲指定の機能を失わせるようである。どおりで、[A-Za-z\-] のような正規表現を見かけるわけだ(これは拡張正規表現では\にもマッチする)。
なお、各言語でも、「aからz または -」に対しては伝統的な [-a-z] [a-z-] という書法も使えるようだ。

また、] という文字を文字クラスに含めるには [ の直後に書くというのは、各言語でも正しく動作する。ただしRubyだけは警告を出す。Rubyが警告を出さないように、

[\]a]

などと書いてみると、これは各言語の「正規表現」では「] または a」の文字クラスであるが、拡張正規表現では \ が特殊文字でないため「\ a ] がこの順に並んだ3文字の文字列」にマッチする([\] は1文字だけからなる文字クラスの指定)。
[ とペアで無い ] が出てきたら普通に「]」の1文字にマッチするというのは各言語の『正規表現」でも大丈夫だが、Rubyはやっぱり警告を出す。しかしRubyも、さすがに [a^b] には警告を出さないようだ。


PerlRubyから正規表現に入門した人は、grep/egrepを使うと戸惑うことがあるかも。まあでも、「特殊文字かどうかわからない文字にはとりあえず \ をつけておけば普通文字になる」という各言語のポリシーはそれはそれでこれらの言語から入門した人にはわかりやすいかも。


他にも何か上位互換性が失われているところがあるんだろうなあ。