正则表达式'(?<=#)[^#]+(?=#)'是如何工作的?

22

我在一个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>用于命名组,但在这种情况下,尖括号从未关闭。
我找不到文档中的?=,而且搜索它确实很困难,因为搜索引擎大多会忽略这些特殊字符。

1
查看此链接以了解关于正则表达式中的“lookaround”的解释:https://dev59.com/9HA85IYBdhLWcg3wCe5Z#2973609 - Amarghosh
3个回答

36
他们被称为环视,它们允许您断言模式是否匹配,而不实际进行匹配。有四个基本的环视:
- 正向环视:查看我们是否可以匹配模式...
- `(?=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#
    \__/      \__/      \____/\___/

参考文献


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

因此,这将匹配两个#之间的所有字符。

顾及到前瞻和后顾在许多情况下非常有用。例如,考虑规则“匹配所有不跟随ab”。你的第一个尝试可能是b[^a],但那是不对的:这也会匹配bus中的buboy中的bo,但你只想要b。而且它不会匹配cab中的b,即使它没有跟随a,因为没有更多的字符可以匹配。

要正确执行此操作,您需要使用前瞻:b(?!a)。这意味着“匹配b但不要在后面匹配a,也不要将其作为匹配的一部分”。因此,它将仅匹配bolo中的b,这正是您想要的;同样它将匹配cab中的b


2
你说:“b(?!a)” - “这个表示‘匹配一个b后面不是a的字符’” - 我认为这有误导性。它的意思是“匹配一个b,在它之后不能匹配到a”。特别地,b实际上不需要跟着任何东西;它绝对不需要跟着[^a]。它可以在字符串的末尾。这就是b(?!a)b(?=[^a])的区别所在。 - polygenelubricants
1
你说得对,那不是最好的措辞。我会编辑以澄清。 - John Feminella

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接