这个问题在这里已经有了答案:
Why does this backreference not work inside a lookbehind?
(1 个回答)
5年前关闭。
TL;DR: Using capturing (and in particular balancing groups) inside .NET's lookbehinds changes the obtained captures, although it shouldn't make a difference. What is it with .NET's lookbehinds that breaks the expected behavior?
我试图想出一个答案 this other question ,作为玩弄 .NET 平衡组的借口。但是,我无法让它们在可变长度的lookbehind 中工作。
首先,请注意我不打算有效地使用这个特定的解决方案。这更多是出于学术原因,因为我觉得可变长度后视发生了一些我不知道的事情。并且知道这在将来会派上用场,当我实际上需要使用这样的东西来解决问题时。
考虑这个输入:
~(a b (c) d (e f (g) h) i) j (k (l (m) n) p) q
目标是匹配括号内的所有字母,这些字母以
~
开头。 ,不管有多深(所以从 a
到 i
的所有内容)。我的尝试是在后视中检查正确的位置,这样我就可以在一次调用 Matches
中获得所有字母。 .这是我的模式:(?<=~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*)[a-z]
在回顾中,我试图找到一个
~(
,然后我使用命名组堆栈 Depth
计算无关的左括号。只要括号在~(
中打开永远不会关闭,后视应该匹配。如果到达那个的右括号,(?<-Depth>...)
无法从堆栈中弹出任何内容,并且后视应该失败(即,对于来自 j
的所有字母)。不幸的是,这不起作用。相反,我匹配 a
, b
, c
, e
, f
, g
和 m
.所以只有这些:~(a b (c) _ (e f (g) _) _) _ (_ (_ (m) _) _) _
这似乎意味着一旦我关闭了一个括号,后视就无法匹配任何东西,除非 我回到我以前去过的最高嵌套级别。
好的,这可能只是意味着我的正则表达式有些奇怪,或者我没有正确理解平衡组。但是后来我在没有后视的情况下尝试了这个。我为每个字母创建了一个字符串,如下所示:
~(z b (c) d (e f (x) y) g) h (i (j (k) l) m) n
~(a z (c) d (e f (x) y) g) h (i (j (k) l) m) n
~(a b (z) d (e f (x) y) g) h (i (j (k) l) m) n
....
~(a b (c) d (e f (x) y) g) h (i (j (k) l) z) n
~(a b (c) d (e f (x) y) g) h (i (j (k) l) m) z
并在每一个上使用这个模式:
~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*z
根据需要,所有情况都匹配,其中
z
替换 a
之间的字母和 i
之后的所有案例都失败了。那么(可变长度)lookbehind 做了什么破坏了平衡组的这种使用?我整个晚上都试图研究这个(并找到了类似 this one 的页面),但我在回顾中找不到它的单一用途。
如果有人可以将我链接到有关 .NET 正则表达式引擎如何在内部处理 .NET 特定功能的一些深入信息,我也会很高兴。我找到了 this amazing article ,但它似乎没有进入(可变长度)lookbehinds,例如。
最佳答案
我想我明白了。
首先,正如我在其中一条评论中提到的,(?<=(?<A>.)(?<-A>.))
从不匹配。
但后来我想, (?<=(?<-A>.)(?<A>.))
怎么样? ?它确实匹配!
怎么样(?<=(?<A>.)(?<A>.))
?与 "12"
匹配, A
是捕获 "1"
,如果我们看看 Captures
收藏,是{"2", "1"}
- 前两个,然后一个 - 反过来。
因此,在lookbehind中,.net从右到左匹配和捕获 .
现在,我们怎样才能让它从左到右捕捉?这很简单,真的 - 我们可以使用前瞻来欺骗引擎:
(?<=(?=(?<A>.)(?<A>.))..)
应用于您的原始模式,我想出的最简单的选择是:
(?<=
~[(]
(?=
(?:
[^()]
|
(?<Depth>[(])
|
(?<-Depth>[)])
)*
(?<=(\k<Prefix>)) # Make sure we matched until the current position
)
(?<Prefix>.*) # This is captured BEFORE getting to the lookahead
)
[a-z]
这里的挑战是现在平衡部分可能会在任何地方结束,所以我们让它一直到达当前位置(像
\G
或 \Z
这样的东西在这里会很有用,但我不认为 .net 有那个)这种行为很可能记录在某处,我会尝试查找。
这是另一种方法。这个想法很简单 - .net 想要从右到左匹配?美好的!拿着它:
(提示: 从底部开始阅读 - 这就是 .net 的做法)
(?<=
(?(Depth)(?!)) # 4. Finally, make sure there are no extra closed parentheses.
~\(
(?> # (non backtracking)
[^()] # 3. Allow any other character
|
\( (?<-Depth>)? # 2. When seeing an open paren, decreace depth.
# Also allow excess parentheses: '~((((((a' is OK.
|
(?<Depth> \) ) # 1. When seeing a closed paren, add to depth.
)*
)
\w # Match your letter
关于.net - 可变长度后视中的平衡组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13389560/