Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8845813
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 14, 20262026-06-14T11:49:24+00:00 2026-06-14T11:49:24+00:00

TL;DR: Using capturing (and in particular balancing groups) inside .NET’s lookbehinds changes the obtained

  • 0

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?

I was trying to come up with an answer to this other question, as an excuse to play around with .NET’s balancing groups. However, I cannot get them to work inside a variable-length lookbehind.

First of all, note that I do not intend to use this particular solution productively. It’s more for academic reasons, because I feel that there is something going on with the variable-length lookbehind which I am not aware of. And knowing that could come in handy in the future, when I actually need to use something like this to solve a problem.

Consider this input:

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

The goal is to match all letters, that are inside parentheses that are preceded by ~, not matter how deep down (so everything from a to i). My attempt was to check for the correct position in a lookbehind, so that I can get all letters in a single call to Matches. Here is my pattern:

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

In the lookbehind I try to find a ~(, and then I use the named group stack Depth to count extraneous opening parentheses. As long as the parenthesis opened in ~( is never closed, the lookbehind should match. If the closing parenthesis to that is reached, (?<-Depth>...) cannot pop anything from the stack and the lookbehind should fail (that is, for all letters from j). Unfortunately, this does not work. Instead, I match a, b, c, e, f, g and m. So only these:

~(a b (c) _ (e f (g) _) _) _ (_ (_ (m) _) _) _

That seems to mean that the lookbehind cannot match anything once I have closed a single parenthesis, unless I go back down to the highest nesting level I have been to before.

Okay, this could just mean there is something odd with my regular expression, or I did not understand the balancing groups properly. But then I tried this without the lookbehind. I created a string for every letter like this:

~(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

And used this pattern on each of those:

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

And as desired, all cases match, where z replaces a letter between a and i and all the cases after that fail.

So what does the (variable-length) lookbehind do that breaks this use of balancing groups? I tried to research this all evening (and found pages like this one), but I could not find a single use of this in a lookbehind.

I would also be glad, if someone could link me to some in-depth information about how the .NET regex engine handles .NET-specific features internally. I found this amazing article, but it does not seem to go into (variable-length) lookbehinds, for instance.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-14T11:49:26+00:00Added an answer on June 14, 2026 at 11:49 am

    I think I got it.
    First, as I mentioned in one of the comments, (?<=(?<A>.)(?<-A>.)) never matches.
    But then I thought, what about (?<=(?<-A>.)(?<A>.))? It does match!
    And how about (?<=(?<A>.)(?<A>.))? Matched against "12", A is captures "1", and if we look at the Captures collection, it is {"2", "1"} – first two, then one – it is reversed.
    So, while inside a lookbehind, .net matches and captures from the right to the left.

    Now, how can we make it capture from left to right? This is quite simple, really – we can trick the engine using a lookahead:

    (?<=(?=(?<A>.)(?<A>.))..)
    

    Applied to your original pattern, the simplest option I came up with was:

    (?<=
        ~[(]
        (?=
            (?:
                [^()]
                |
                (?<Depth>[(])
                |
                (?<-Depth>[)])
            )*
            (?<=(\k<Prefix>))   # Make sure we matched until the current position
        )
        (?<Prefix>.*)           # This is captured BEFORE getting to the lookahead
    )
    [a-z]
    

    The challenge here was that now the balanced part may end anywhere, so we make it reach all the way to the current position (Something like \G or \Z would be useful here, but I don’t think .net has that)

    It is very possible this behavior is documented somewhere, I’ll try to look it up.

    Here’s another approach. The idea is simple – .net wants to match from right to left? Fine! Take that:
    (tip: start reading from the bottom – that is how .net does it)

    (?<=
        (?(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
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I want to make little high-performance recording application. For capturing, I will be using
We are capturing a visible tab in a Chrome browser (by using the extensions
I'm having trouble capturing the digits in a string of this format (t|b|bug_|task_|)1234 using
I am using a capturing software, Abbyy FlexiCapture, after user done the verification (some
We are capturing packets to a file using tcpdump() . I need to write
I am using the Thumbalizr API for capturing website screenshots. I am trying to
I was capturing my own packets from my iPhone 4 when I was using
Using Regex in .Net I will have a set of data that comes in
I am capturing image using canvas and i want to store a captured image
I am capturing images using MediaStore.ACTION_IMAGE_CAPTURE intent. it is working fine in most of

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.