文字クラス交差演算子&&
は、その関数の定義により可換でなければなりません。a および b と[a&&b]
まったく同じ文字に一致する必要があります。[b&&a]
次のパターンはすべてこの基準を満たしていることがわかりました。
[a-z&&abcd]
と同じ[abcd&&a-z]
[a-z&&ab[cd]]
と同じ[ab[cd]&&a-z]
[a-z&&[ab][cd]]
と同じ[[ab][cd]&&a-z]
それらはすべて と同等[abcd]
です。ただし、 と表現する[a-z&&[ab]cd]
と、これは当てはまりません。その式は and のみに一致し、 c
andには一致しd
ません。ただし、反転バージョンは、他のパターンと同様に 4 つの文字すべてに一致します。言い換えるとa
b
[[ab]cd&&a-z]
[[ab]cd&&a-z]
と同じではない[a-z&&[ab]cd]
Pattern
これがなぜなのかを調べるために のソースを調べたところ、これが交差の実装方法であることがわかりました (Java 1.8.0_60 JDK)
case '&':
// ...
ch = next();
if (ch == '&') {
ch = next();
CharProperty rightNode = null;
while (ch != ']' && ch != '&') {
if (ch == '[') {
if (rightNode == null)
rightNode = clazz(true);
else
rightNode = union(rightNode, clazz(true));
} else { // abc&&def
unread();
rightNode = clazz(false); // here is what happens
}
ch = peek();
}
マークされた行が
rightNode = clazz(false);
そしてそうではない
rightNode = union(rightNode, clazz(true));
つまり、 の右側で&&
は、ネストされた文字クラス内にない最初の文字が検出されるたびに、パターン パーサーはその前に何もないと見なします。そのため、 の後&&
、パーサーは を読み取り[ab]
、rightNode
次に を読み取りますcd
が、 とマージする代わりに、[ab]
上書きするだけです。
のような正規表現を実際に書く人はいないことは知っています[a-z&&[ab]cd]
が、それでもドキュメントはそれが機能するはずであることを暗示しています。これは実装のバグですか、それとも実際にこのように動作するはずですか?