正则表达式,用于执行用户代理字符串变体的命名捕获

时间:2013-10-22 22:23:26

标签: regex pcre

我正在尝试提供一个正则表达式,能够将整个用户代理字符串捕获为以下列两种格式之一登录的单个命名组:

Mozilla/5.0+(compatible;+MSIE+9.0;+Windows+NT+6.1;+WOW64;+Trident/5.0)
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"

注意:使用第二种格式时,我不希望捕获引号。

在这里使用一些变更似乎是正确的方法,所以我觉得这样的事情会起作用:

(?:"(?<user_agent>[^"]+)")|(?<user_agent>[^\s]+)

但事实并非如此。它似乎没有捕获任何东西。我在这里显然遗漏了一些东西。

以下几乎可以工作 - 至少它捕获了一些东西 - 但它没有执行命名捕获(我需要):

(?:"([^"]+)")|([^\s]+)

其他说明(如果重要):

  • 我正在使用PCRE引擎。
  • 两个用户代理字符串变体都将具有单个前导空格和单个尾随空格。
  • 我一直用于测试的工具(我发现它非常可靠)住在这里:http://gskinner.com/RegExr/

这似乎应该真的简单,但我怀疑我误解了命名组之间的交替是如何工作的。


更新

作为澄清,用户代理字符串之前和之后也会有内容,如下所示:

some-content-before Mozilla/5.0+(compatible;+MSIE+9.0;+Windows+NT+6.1;+WOW64;+Trident/5.0) some-content-after
some-content-before "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)" some-content-after

这很重要,因为名为capture group的用户代理字符串不应捕获之前的内容或之后的内容,因为它们将通过自己的命名捕获组捕获。

1 个答案:

答案 0 :(得分:1)

命名捕获不起作用,因为默认情况下,PCRE引擎不会接受相同的命名捕获超过1次。但您可以使用(?J)修饰符更改此行为,例如:

(?J)(?:"(?<user_agent>[^"]+)")|(?<user_agent>\S+)

另一种方法是使用分支重置功能(?|...(..)...|...(..)...),其中“两个捕获组”实际上是多个版本的交替中的唯一捕获组:

(?|"(?<user_agent>[^"]+)"|(?<user_agent>\S+))

请注意,gskinner的实现不完整,但您可以使用此测试人员查看结果:http://regex.larsolavtorvik.com/

很好,你可以避免使用这些模式重复命名捕获(对于你的示例字符串)的问题:

("?)(?<user_agent>[^"]+|\S+)\1

(?<user_agent>[^"\r\n]+)