【问题标题】:How does the regular expression ‘(?<=#)[^#]+(?=#)’ work?正则表达式‘(?<=#)[^#]+(?=#)’是如何工作的?
【发布时间】:2010-06-22 11:55:52
【问题描述】:

我在 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 `?=`?

所以我遇到的问题是?&lt;=?&lt; 部分。通过阅读 MSDN,?&lt;name&gt; 用于命名组,但在这种情况下,尖括号永远不会闭合。

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

【问题讨论】:

标签: regex lookahead lookbehind lookaround


【解决方案1】:

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

  • 正面观察:看看我们是否可以匹配pattern...
    • (?=pattern) - ...当前位置右侧(向前看
    • (?&lt;=pattern) - ...在当前位置的左边(看后面
  • 否定的lookarounds - 看看我们是否不能匹配pattern
    • (?!pattern) - ...在右边
    • (?&lt;!pattern) - ...到左边

作为一个简单的提醒,让我们看看:

  • =正面!负面
  • &lt; 是看后面,否则是看前面

参考文献


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

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

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

考虑以下输入字符串:

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

现在,#([a-z]+)# 将给出以下匹配项 (as seen on rubular.com):

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

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

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

很遗憾,这无法在 rubular.com 上演示,因为它不支持后视。但是,它确实支持前瞻,因此我们可以使用匹配 (as seen on rubular.com) 的#([a-z]+)(?=#) 做类似的事情:

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

参考文献

【讨论】:

    【解决方案2】:

    正如另一张海报提到的,这些是 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 在很多情况下都非常有用。例如,考虑规则“匹配所有bs,而不是a”。您的第一次尝试可能类似于b[^a],但这是不对的:这也将匹配bus 中的buboy 中的bo,但您只想要b。并且它不会匹配cab 中的b,即使它后面没有a,因为没有更多字符可以匹配。

    要正确执行此操作,您需要一个前瞻:b(?!a)。这表示“匹配b,但之后不匹配a,并且不要将其作为匹配的一部分”。因此它只会匹配bolo 中的b,这就是你想要的;同样,它会匹配cab 中的b

    【讨论】:

    • 你说:b(?!a) - “这说'匹配一个b,后跟一个不是a'” - 我认为这是误导,实际上。它说“匹配一个b,之后你就不能匹配一个a。”特别是,b 并不一定要跟任何东西。 [^a] 绝对不必跟在它后面。它可以在字符串的末尾。这就是b(?!a)b(?=[^a]) 的不同之处。
    • 你说得对,这不是最好的措辞。我将进行编辑以澄清。
    【解决方案3】:

    【讨论】:

      猜你喜欢
      • 2021-09-03
      • 2011-03-20
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 2013-03-29
      • 2017-07-14
      • 1970-01-01
      相关资源
      最近更新 更多