regex 在可变长度后看中平衡组[重复]

vxf3dgd4  于 2023-08-08  发布在  其他
关注(0)|答案(2)|浏览(72)

此问题在此处已有答案

Why does this backreference not work inside a lookbehind?(1个答案)
7年前关闭。

**TL;DR:**在.NET的lookbehinds中使用捕获(特别是平衡组)会改变所获得的捕获,尽管它不应该有什么区别。.NET的lookbehinds破坏了预期的行为是什么?

我试图想出一个this other question的答案,作为玩.NET平衡组的借口。但是,我不能让它们在可变长度的向后看中工作。
首先,请注意,我并不打算有效地使用这个特定的解决方案。这更多的是出于学术原因,因为我觉得可变长度的向后看有一些我没有意识到的东西。而且知道这在将来可能会派上用场,当我真正需要用这样的东西来解决一个问题的时候。
考虑以下输入:

~(a b (c) d (e f (g) h) i) j (k (l (m) n) p) q

字符串
目标是匹配所有在括号中前面有~的字母,不管深度有多深(从ai的所有字母)。我的尝试是在lookbehind中检查正确的位置,以便可以在对Matches的单个调用中获得所有字母。以下是我的模式:

(?<=~[(](?:[^()]*|(?<Depth>[(])|(?<-Depth>[)]))*)[a-z]


在lookbehind中,我试图找到一个~(,然后使用命名组堆栈Depth来计算无关的左括号。只要在~(中打开的括号从未关闭,则lookbehind应该匹配。如果到达了右括号,(?<-Depth>...)将无法从堆栈中弹出任何内容,并且lookbehind将失败(即,对于来自j的所有字母)。不幸的是,这不起作用。相反,我匹配abcefgm。所以只有这些:

~(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替换了ai之间的字母,并且之后的所有大小写都失败。
那么,(可变长度的)向后看做了什么来打破平衡组的这种使用呢?我整个晚上都在研究这个问题(找到了像this one这样的页面),但是我在回顾中找不到这个问题的任何用途。
我也很高兴,如果有人能把我链接到一些关于.NET正则表达式引擎如何在内部处理. NET特定功能的深入信息。例如,我找到了this amazing article,但它似乎没有进入(可变长度)查找。

3gtaxfhh

3gtaxfhh1#

我想我明白了
首先,正如我在其中一条评论中提到的,(?<=(?<A>.)(?<-A>.))永远不会匹配。
但后来我想,(?<=(?<-A>.)(?<A>.))呢?它匹配!
那么(?<=(?<A>.)(?<A>.))呢?与"12"匹配,A捕获"1",如果我们看一下Captures集合,它是{"2", "1"}-前两个,然后一个-它是相反的。

因此,在lookbehind中,.net从右到左进行匹配和捕获

现在,我们如何使它从左到右捕获?这很简单,真的-我们可以使用lookahead欺骗引擎:

(?<=(?=(?<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想要从右到左匹配?好吧!听着:
(tip:从底部开始阅读-.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

zpf6vheq

zpf6vheq2#

我认为问题出在数据上,而不是模式上。数据中有需要匹配的“Post”项,例如
(a B(c)d e f)
其中需要匹配d、e和f。一个更平衡的数据
(a B(c)(d)(e)(f))
因此,我对这个示例数据采取的策略需要在大括号后面有一个匹配后的情况:
~(2-x)(x,y)(
J & K应该被忽略的地方...我的模式失败了,捕获了它们。
有趣的是,我给捕获组命名是为了找出它们是从哪里来的,j和k在捕获三中出现。我留给你的不是一个答案,而是一个尝试,看看你是否可以改进它。

(~                         # Anchor to a Tilde
 (                         # Note that \x28 is ( and \x29 is )      
  (                          # --- PRE ---
     (?<Paren>\x28)+          # Push on a match into Paren
     ((?<Char1>[^\x28\x29])(?:\s?))*
   )+                         # Represents Sub Group 1
  (                           #---- Closing
   ((?<Char2>[^\x28\x29])(?:\s?))*
   (?<-Paren>\x29)+           # Pop off a match from Paren

  )+  
  (
     ((?<Char3>[^\x28\x29])(?:\s?))*   # Post match possibilities
  )+

 )+
(?(Paren)(?!))    # Stop after there are not parenthesis    
)

字符串
这是我自己创建的一个工具(也许有一天我会出版)。请注意,表示空格匹配的位置。

Match #0
               [0]:  ~(a˽b˽(c)˽d˽(e˽f˽(g)˽h)˽i)˽j˽k
       ["1"] → [1]:  ~(a˽b˽(c)˽d˽(e˽f˽(g)˽h)˽i)˽j˽k
       →1 Captures:  ~(a˽b˽(c)˽d˽(e˽f˽(g)˽h)˽i)˽j˽k
       ["2"] → [2]:  (e˽f˽(g)˽h)˽i)˽j˽k
       →2 Captures:  (a˽b˽(c)˽d˽, (e˽f˽(g)˽h)˽i)˽j˽k
       ["3"] → [3]:  (g
       →3 Captures:  (a˽b˽, (c, (e˽f˽, (g
       ["4"] → [4]:  g
       →4 Captures:  a˽, b˽, c, e˽, f˽, g
       ["5"] → [5]:  ˽i)
       →5 Captures:  ), ), ˽h), ˽i)
       ["6"] → [6]:  i
       →6 Captures:  ˽, h, ˽, i
       ["7"] → [7]:  
       →7 Captures:  ˽d˽, , ˽j˽k, 
       ["8"] → [8]:  k
       →8 Captures:  ˽, d˽, ˽, j˽, k
   ["Paren"] → [9]:  
  ["Char1"] → [10]:  g
      →10 Captures:  a, b, c, e, f, g
  ["Char2"] → [11]:  i
      →11 Captures:  ˽, h, ˽, i
  ["Char3"] → [12]:  k
      →12 Captures:  ˽, d, ˽, j, k

相关问题