.net - 可变长度后视中的平衡组

标签 .net regex lookaround balancing-groups

这个问题在这里已经有了答案:





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

目标是匹配括号内的所有字母,这些字母以 ~ 开头。 ,不管有多深(所以从 ai 的所有内容)。我的尝试是在后视中检查正确的位置,这样我就可以在一次调用 Matches 中获得所有字母。 .这是我的模式:
(?<=~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*)[a-z]

在回顾中,我试图找到一个 ~( ,然后我使用命名组堆栈 Depth计算无关的左括号。只要括号在~(中打开永远不会关闭,后视应该匹配。如果到达那个的右括号,(?<-Depth>...)无法从堆栈中弹出任何内容,并且后视应该失败(即,对于来自 j 的所有字母)。不幸的是,这不起作用。相反,我匹配 a , b , c , e , f , gm .所以只有这些:
~(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/

相关文章:

.net - TargetType ="controlType"和 TargetType ="{x:Type controlType}"之间的区别

PHP - 检测字符串之间的空格

python - 正则表达式将字符添加到匹配的字符串

正则表达式在一个搜索词之后和其他两个搜索词之一之前(以先到者为准)收集数据

c# - "interface based programming"到底是什么?

c# - 如何添加和检索 Azure Blob 的附加信息

c# - 在可变数量的字符之后分割字符串

javascript - 正则表达式 - 仅当字符未继续或后跟相同字符时才匹配字符

python - Python 正则表达式中可变宽度回顾的替代方案

javascript - 捕获 url 前缀但排除 www 的正则表达式