.NET FrameworkのRegexの文字クラスはバグっているのか?
はじめに
正規表現のお話ですが、『.
は任意の一文字にマッチする』みたいな文法解説ではありません。
そんなの大手サイトが死ぬほど書いてますしね。
妙なバグを踏み抜くことに定評がある弊社ですが、今回は正規表現の文字クラス関係でわりと意味がわからないバグを踏み抜いたのでそれについてです。
.NET Frameworkの正規表現の互換性
正規表現にはいくつかの系統というか規格(PosixとかJavaScript)が存在しますが、.NETはどこに属しているのでしょうか?
.NET Framework では、正規表現のパターンが特殊な構文または言語で定義されます。この構文または言語には、Perl 5 の正規表現と互換性があるほか、右から左への一致処理など、いくつかの機能が追加されています。
ということでPerl 5と互換性があると言っています。信じて良いんですね?
検証環境
ということで楽しい検証の時間です。
それぞれの言語で以下のサイトを使用しました。
- .NET Framework - Regex Storm
- Mono(mono-4.2.1 (C#5, CLI4.5)) - paiza.IO
- JavaScript - regexper、regex101
- PCRE - regex101
また、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では受容されます。
さらにA
〜Z
と_
のみにマッチするという不可解な挙動をします。面白くなってきましたね。
[A-Z-[ ]]
PCRE・JavaScriptではZ]
、[]
、]
、A]
などにマッチしますが、.NET・monoでは相変わらずA
やZ
などの単独の文字にしかマッチしません。
-[ ]
をどこにやった?
おわりに
普通なら思いつかないような謎正規表現をプロダクト環境にぶち込んでくる人がいるので、世の中は多様性で満ち溢れていますね。
バグか他の文法との兼ね合いなのかが分かりませんでしたが、仮にバグだとしても後方互換性を維持するために直すのは難しそうですね。
完全に余談ですが、仮に正規表現が超複雑になるようなものを解析しないといけない場合はIronyやSpracheなんかを使ったほうが後々幸せかもしれません。
おわり