14

TL;DR: .NET の後読み内でキャプチャ (特にバランシング グループ) を使用すると、取得したキャプチャが変更されますが、違いはありません。.NET の後読みが予期した動作を妨げる原因は何ですか?

.NET のバランシング グループをいじる言い訳として、この他の質問に対する答えを見つけようとしていました。ただし、可変長の後読み内でそれらを機能させることはできません。

まず、この特定のソリューションを生産的に使用するつもりはないことに注意してください。それは学術的な理由によるものです。なぜなら、私が気付いていない可変長後読みで何かが起こっていると感じているからです。将来、問題を解決するためにこのようなものを実際に使用する必要がある場合に、それが役立つ可能性があることを知っています.

次の入力を検討してください。

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

目標は、 が前にある括弧内にあるすべての文字に一致することです (つまり、からまで~のすべて)。私の試みは、後読みで正しい位置を確認することでした。これにより、 への 1 回の呼び出しですべての文字を取得できます。これが私のパターンです:aiMatches

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

後読みで を見つけようとしてから~(、名前付きグループ スタックを使用してDepth不要な開き括弧を数えます。で開いた括弧~(が決して閉じない限り、後読みは一致するはずです。への閉じ括弧に達した場合、(?<-Depth>...)はスタックから何もポップできず、後読みは失敗します (つまり、 からのすべての文字に対してj)。残念ながら、これは機能しません。代わりにabcefgおよびに一致し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の間の文字を置換し、その後のすべてのケースが失敗します。ai

では、(可変長の) 後読みは、このバランシング グループの使用を破るものでしょうか? 私はこれを一晩中調査しようとしましたが (そして、このようなページを見つけまし)、後読みでこれを 1 回も使用する方法を見つけることができませんでした。

また、.NET 正規表現エンジンが .NET 固有の機能を内部でどのように処理するかについての詳細な情報に誰かが私をリンクしてくれたら嬉しいです。この素晴らしい記事を見つけましたが、たとえば、(可変長の) 後読みには入っていないようです。

4

2 に答える 2

13

私はそれを手に入れたと思います。
まず、コメントの 1 つで述べたように、(?<=(?<A>.)(?<-A>.))一致することはありません。
しかし、私は考えました(?<=(?<-A>.)(?<A>.))。似合ってます!
そしてどう(?<=(?<A>.)(?<A>.))ですか?Matchedは capturesです。コレクションを見ると、"12"最初は2 つ、次に 1 つです。逆になっています。そのため、後読みの内部では、.net は右から左に一致してキャプチャします。A"1"Captures{"2", "1"}

では、左から右にキャプチャするにはどうすればよいでしょうか。これは非常に単純です。先読みを使用してエンジンをだますことができます。

(?<=(?=(?<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
于 2012-11-16T23:11:26.937 に答える
2

問題はパターンではなくデータにあると思います。データには、次のような一致する必要がある「投稿」項目があります

(ab ( c ) def )

ここで、de と f を一致させる必要があります。よりバランスの取れたデータは

(ab (c)(d)(e)(f))


したがって、この例のデータで採用したタックには、中かっこの後に一致後の状況が必要でした。

~(ab (c) d (ef (g) h) i) jk

j & k は無視する必要があります...私のパターンは失敗し、それらをキャプチャしました。

興味深いのは、キャプチャ グループに名前を付けて、それらがどこに入ったのかを調べたことです。j と k はキャプチャ 3 に含まれていました。答えではなく、改善できるかどうかを確認する試みを残します.

(~                         # 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
于 2012-11-15T04:37:20.593 に答える