次の正規表現が一部の文字列で機能し、他の一部の文字列では機能しない理由が不思議です。
/^([0-3]+)(?!4|.*5)[0-9]+$/
1151 -> これは一致しません
1141 -> これは一致しますが、なぜですか? .* を空と見なすことができるので、正規表現は次のようになります/^([0-3]+)(?!4|5)[0-9]+$/
先読みの仕組みを誤解していると思います...
次の正規表現が一部の文字列で機能し、他の一部の文字列では機能しない理由が不思議です。
/^([0-3]+)(?!4|.*5)[0-9]+$/
1151 -> これは一致しません
1141 -> これは一致しますが、なぜですか? .* を空と見なすことができるので、正規表現は次のようになります/^([0-3]+)(?!4|5)[0-9]+$/
先読みの仕組みを誤解していると思います...
正規表現が文字列をどのように解析するかを、順を追って見ていきましょう。
^([0-3]+)(?!4|.*5)[0-9]+$
まず、いくつかの説明。またはが最後に消費された文字に続く(?!4|.*5)
かどうかをチェックする否定的な先読みです。そうである場合、現在の一致は失敗し、後退します。また、正確にどのように影響するかをもう少し明確にしたい場合にも使用できます。 4
.*5
(?!(4|.*5))
|
見ることから始めましょう1141
まず、[0-3]+
可能な限り多くの文字を消費するため、最大で11
inを消費し1141
ます。残っているのは41
. 4
正規表現は現在の文字の後にあるかどうかを確認する?!
ようになりました。 は否定的な先読みであるため、見つかった場合、一致は失敗します。followingで4
ある11
ため、一致は失敗し、正規表現は後退して再試行します。
2 つのに一致する代わりに、1 つ1
の一致を試行し、残ったものと一致1
するようになり141
ました。?!4
次の文字があることを確認するためにチェックし4
、何を知っていますか、そこにはありません。一致しなかったため、正規表現は否定的な先読みを残し、残りの正規表現に進みます。141
は最終的に一致するため、文字列[0-9]+
全体が一致します。ルックアラウンドは文字を消費しないことに注意してください。1141
それでは見てみましょう1151
前回と同じことが起こり、11
消費されて51
余ってしまいました。次に、否定先読みを見て、それから残りの文字列を評価します。明らかに、4
はこの文字列のどこにもないので無視できます.*5
。
したがって、先読み.*5
は と一致しようとし51
ます。一致してしまうと、前と同じように一致が失敗し、正規表現が後退します。正規表現を少しでも知っていれば、空と評価される可能性があるため.*5
、の先頭に一致することは明らかです。51
.*
一歩下がって、今度は1
両方ではなく 1 つを一致させ、再び否定的な先読みを行います。
現在、 を消費していますが1
、まだ151
一致する必要が(?!4|.*5)
あり、正規表現の一部になっています。ここで、4
は明らかに文字列に存在しないため、一致しません.*5
。もう一度見てみましょう。
.*5
will match a portion of 151
since .*
will consume the first 1
, and the 5
will finish off by matching 5
. This should also be obvious if you know regex.
So we've made a match in a negative look-ahead again, which is bad... so we step back again. We have no more integers to attempt to match with [0-3], and since you can't match 0 integers with a +
, the entire string fails to match the regular expression.
1141
これは、正規表現エンジンが11
との[0-3]+
一致から最初のとの一致1
に戻り、残りの数字を[0-9]+
.
最初の文字の後の次の文字1
は1
and not4
であるため、次の文字のみを見る否定的な先読みは一致を妨げません。
が追加された負の1151
先読み.*
によって防止されるため、 は一致しません。
先読みの.*
前に put を追加すると、「次の文字が の場合は一致しない」 、または任意の数の文字の後に次の文字が' (改行を無視) の場合は一致しません。 5
4
5
したがって、エンジンが の最初の部分[0-3]+
だけを一致させるためにバックトラックしたとしても、文字列にはまだ前方があるため、一致は妨げられます。1
1151
5
先読みと後読みはゼロ幅であることに注意してください。
それはどの正規表現のフレーバーですか?
/^([0-3]+) (?!4|.*5) [0-9]+$/
正直なところ、1151 ではなく 1141 に一致する唯一の方法は、正規表現の強調表示された部分が として評価される場合NOT 4 or .* followed by 5
です。その場合、正規表現エンジンは1141
4 に一致するため一致を見つけることができませんが、内部一致を完了するために 5 を見逃すことになります。
ただし、エンジンが一致を機能させたい場合、この表現は非常に強力であることが証明されるため、通常、代替は4
or .*5
- として理解されますが、これはまだ 4 または 5 と同等ではありません。.*
式を何でテストしていますか?
4または5に一致させたい場合、最良のオプションは
/^[0-3]+[45][0-9]+$/
しかし、それが何をすべきかについてのより良い説明がなければ、それ以上のことを提案するのは難しいです...