1

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

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

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

4

1 回答 1

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]+)
于 2013-10-24T07:42:11.563 回答