問題
問題は.*
、オプションの前にあることです(Trident/\d\.\d)
。(Trident/\d\.\d)
正規表現エンジンは、あきらめる前に一致するものがあるかどうかをチェックしようとせず、オプションのグループを空の文字列として一致させます。
このトレースは、正規表現エンジンがどのように機能するかを示します。
が一致した後.*MSIE (\d+\.\d+)
、残りのテキストは次のとおりです。
; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
.*
貪欲なので、文字列の最後まですべてに一致します。テキストが残っていません。
(Trident/\d\.\d)?
貪欲なので、Trident/\d\.\d
最初に一致しようとしますが、失敗しました。ただし、空の文字列と一致する可能性があります (空の文字列は、行末であっても、どこにでもある可能性があります)。したがって、この部分で空文字列が一致します。
.*
行末にいるため、空の文字列にも一致します。
.*
途中で遅延量指定子に変更する.*MSIE (\d+\.\d+).*?(Trident/\d\.\d)?.*
と、同じ理由で機能しなくなります。
一致した後.*MSIE (\d+\.\d+)
は、まあ、同じことです。
.*?
は怠惰なので、最初に空の文字列を試します。残りのテキストは上記と同じです (何も消費されません)。
(Trident/\d\.\d)?
貪欲で、(Trident/\d\.\d)
最初に試行して失敗し、空の文字列と一致します。
.*
文字列の残りの部分に一致.*MSIE (\d+\.\d+)
します。
ソリューション
(Trident/\d\.\d)
簡単な方法を取る前にエンジンに強制的にチェックさせるために、全体を.*(Trident/\d\.\d)
オプションにすることができます。これにより、エンジンは一致するすべての可能性をチェックするように促され、(Trident/\d\.\d)
あきらめて空の文字列に満足する前に。
.*MSIE (\d+\.\d+)(.*(Trident/\d\.\d))?
正規表現のトレース:
エンジンが非キャプチャ グループをサポートしている場合:
.*MSIE (\d+\.\d+)(?:.*(Trident/\d\.\d))?
必要なのは だけなのでTrident...
、全体をキャプチャする必要はありません。