21

我在 C# 程序中有以下正则表达式,并且难以理解它:

(?<=#)[^#]+(?=#)

我将其分解为我认为我理解的内容:

(?<=#)    a group, matching a hash. what's `?<=`?
[^#]+     one or more non-hashes (used to achieve non-greediness)
(?=#)     another group, matching a hash. what's the `?=`?

所以我遇到的问题是?<=?<部分。从阅读 MSDN,?<name>用于命名组,但在这种情况下,尖括号永远不会关闭。

我在文档中找不到?=,搜索它真的很困难,因为搜索引擎大多会忽略那些特殊字符。

4

3 回答 3

34

它们被称为环视;它们允许您断言模式是否匹配,而无需实际匹配。有 4 种基本外观:

  • 积极的环顾四周:看看我们是否可以匹配pattern...
    • (?=pattern)- ...当前位置右侧向前看
    • (?<=pattern)- ...在当前位置的左侧向后看)
  • 负面的环视 - 看看我们是否无法匹配pattern
    • (?!pattern)- ...向右
    • (?<!pattern)- ...向左

作为一个简单的提醒,环顾四周:

  • =的,!负的
  • <向后看,否则是向前看

参考


但是为什么要使用环视呢?

有人可能会争辩说,上述模式中的环视不是必需的,并且#([^#]+)#可以很好地完成工作(提取由捕获的字符串\1以获取非#- )。

不完全的。不同之处在于,由于环视与 不匹配#因此下次尝试查找匹配时可以再次“使用”它。简单地说,环视允许“匹配”重叠。

考虑以下输入字符串:

and #one# and #two# and #three#four#

现在,#([a-z]+)#将给出以下匹配项(如 rubular.com 上所见):

and #one# and #two# and #three#four#
    \___/     \___/     \_____/

将此与(?<=#)[a-z]+(?=#)匹配的 进行比较:

and #one# and #two# and #three#four#
     \_/       \_/       \___/ \__/

不幸的是,这无法在 rubular.com 上演示,因为它不支持后视。但是,它确实支持前瞻,所以我们可以用 , 做类似的事情#([a-z]+)(?=#)如在 rubular.com 上看到的):

and #one# and #two# and #three#four#
    \__/      \__/      \____/\___/

参考

于 2010-06-22T12:18:04.710 回答
4

正如另一张海报所提到的,这些是lookarounds,用于更改匹配内容和时间的特殊构造。这说:

(?<=#)    match but don't capture, the string `#`
            when followed by the next expression

[^#]+     one or more characters that are not `#`, and

(?=#)     match but don't capture, the string `#`
            when preceded by the last expression

所以这将匹配两个#s 之间的所有字符。

Lookaheads 和lookbehinds 在很多情况下都非常有用。例如,考虑规则“匹配所有b不跟随 的 s a”。您的第一次尝试可能类似于b[^a],但这是不对的:这也将匹配buinbusboin boy,但您只想要b. 并且它不会匹配bin cab,即使它后面没有跟着 an a,因为没有更多的字符可以匹配。

要正确地做到这一点,你需要一个前瞻:b(?!a). 这表示“匹配 ab但之后不匹配 an a,并且不要使那部分成为匹配”。因此它只会匹配bin bolo,这就是你想要的;同样它会匹配bin cab

于 2010-06-22T12:04:02.220 回答
1

它们被称为环视http ://www.regular-expressions.info/lookaround.html

于 2010-06-22T11:57:22.123 回答