.NET FrameworkのRegexの文字クラスはバグっているのか?

はじめに

正規表現のお話ですが、『.は任意の一文字にマッチする』みたいな文法解説ではありません。 そんなの大手サイトが死ぬほど書いてますしね。

妙なバグを踏み抜くことに定評がある弊社ですが、今回は正規表現の文字クラス関係でわりと意味がわからないバグを踏み抜いたのでそれについてです。

.NET Framework正規表現の互換性

正規表現にはいくつかの系統というか規格(PosixとかJavaScript)が存在しますが、.NETはどこに属しているのでしょうか?

.NET Framework の正規表現

.NET Framework では、正規表現のパターンが特殊な構文または言語で定義されます。この構文または言語には、Perl 5 の正規表現と互換性があるほか、右から左への一致処理など、いくつかの機能が追加されています。

ということでPerl 5と互換性があると言っています。信じて良いんですね?

検証環境

ということで楽しい検証の時間です。

それぞれの言語で以下のサイトを使用しました。

また、paiza.IOはオンラインの開発環境でRegexテスターではないので以下のコードでテストをしました。

余談ですが、補完文字列はC#6からの機能のはずですが、C#5のはずpaiza.IOで使えてます。 更に余談ですが、mono-4.2.1で補完文字列のバグが修正されてるってリリースノートに書いてあります。なにこれ?

using System;
using System.Text.RegularExpressions;

public class Hello
{
    public static void Main()
    {
        foreach(Match it in Regex.Matches("テスト文字列","正規表現"))
        {
            Console.WriteLine($"\"{it.Value}\"");
        }
    }
}

[]

空の文字クラスは.NET・mono・PCREでは受容されませんが、JavaScriptでは受容されます。 まぁ順当な結果ですね。

[5-3]

逆順の文字クラスは.NET・mono・PCRE・JavaScriptの全てで受容されませんでした。 当たり前ですね。

[Z-[]]

Z[[]にマッチするという表現でPCRE・JavaScriptでは問題なく動作しますが、.NET・monoではUnterminated [] set.ということで弾かれます。 はぁ、そうですか。

[Z-[ ]]

『.NET・monoでは空の文字クラスが弾かれてたじゃん。じゃあ[]にスペース入れれば動くんじゃね?』がまじで動いたパターン。

PCRE・JavaScriptではZ][]]のパターンにマッチしますが、.NET・monoではZのみにマッチします。

[A-Z_-[ ]]

大文字のAからZ_から[のいずれかと]にマッチするという表現はそもそも_>]なので受容されないはずですが、.NET・monoでは受容されます。

さらにAZ_のみにマッチするという不可解な挙動をします。面白くなってきましたね。

[A-Z-[ ]]

PCRE・JavaScriptではZ][]]A]などにマッチしますが、.NET・monoでは相変わらずAZなどの単独の文字にしかマッチしません。 -[ ]をどこにやった?

おわりに

普通なら思いつかないような謎正規表現をプロダクト環境にぶち込んでくる人がいるので、世の中は多様性で満ち溢れていますね。

バグか他の文法との兼ね合いなのかが分かりませんでしたが、仮にバグだとしても後方互換性を維持するために直すのは難しそうですね。

完全に余談ですが、仮に正規表現が超複雑になるようなものを解析しないといけない場合はIronySpracheなんかを使ったほうが後々幸せかもしれません。

おわり