Unless you are using .NET, lookbehinds have to be of fixed length. Since you just want to detect whether there are any unmatched closing brackets, you don't actually need a lookbehind though:
^[^\[\]]*(?:\[[^\[\]]*\][^\[\]]*)*\]
If this matches you have an unmatched closing parenthesis.
It's a bit easier to understand, if you realise that [^\[\]]
is a negated character class that matches anything but square brackets, and if you lay it out in freespacing mode:
^ # start from the beginning of the string
[^\[\]]* # match non-bracket characters
(?: # this group matches matched brackets and what follows them
\[ # match [
[^\[\]]* # match non-bracket characters
\] # match ]
[^\[\]]* # match non-bracket characters
)* # repeat 0 or more times
\] # match ]
So this tries to find a ]
after matching 0 or more well-matched pairs of brackets.
Note that the part between ^
and ]
is functionally equivalent to Tim Pietzker's solution (which is a bit easier to understand conceptually, I think). What I have done, is an optimization technique called "unrolling the loop". If your flavor provides possessive quantifiers, you can turn all *
into *+
to increase efficiency even further.
About your attempt
Even if you are using .NET, the problem with your pattern is that .
allows you to go past other brackets. Hence, you'd get no match in
[abc]def]
Because both the first and the second ]
have a [
somewhere in front of them. If you are using .NET, the simplest solution is
(?<!\[[^\[\]]*)\]
Here we use non-bracket characters in the repetition, so that we don't look past the first [
or ]
we encounter to the left.