我的正则表达式是.*MSIE (\d+\.\d+).*(Trident/\d\.\d)?.*
要匹配的字符串:
Mozilla/4.0 (compatible; MSIE 7.0; 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)
所以我希望第2组包含Trident / 5.0的值。但是即将出现。我有什么问题在这里做错了吗?如果我在?
之后删除(Trident/\d\.\d)
,则会将其作为第2组选中。
答案 0 :(得分:3)
问题是可选.*
前面有(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/\d\.\d)
。如果输入字符串中有模式,它肯定会找到匹配项。如果没有,.*(Trident/\d\.\d)
将失败,我们将使用空字符串。
如果您的引擎支持非捕获组:
.*MSIE (\d+\.\d+)(?:.*(Trident/\d\.\d))?
由于您只需要Trident...
,我们无需捕捉整个事情。
答案 1 :(得分:2)
你实际上已经解决了这个问题。 。 。与“删除?” 。 。 。如果(Trident/\d\.\d)
是可选的,则.*MSIE (\d+\.\d+).*(Trident/\d\.\d)?.*
与.*MSIE (\d+\.\d+).*
实际上没有区别。
最简单的解决方法是将其分解为两个搜索:MSIE (\d+\.\d+)
和(Trident/\d\.\d)
。您可以执行更复杂的单一匹配,但为了简单起见,您可能希望使用两个单独的匹配。