Hello Daniel and Andreas, and All,
As soon as you’re looking for couples (), [], {}, <>… in a text, containing unlimited nested respective couples (), [], {}, <>, you absolutely need to use a very strong feature of PCRE regex : the recursive patterns. If you don’t, it quite impossible to handle any arbitrary nesting depth !
Generally speaking, you automatically create a recursive pattern, when you add a recursive call to a group, located INSIDE the sub-pattern whose it makes a reference.
For instance, let’s suppose the general regex ....(....(?n)....).... and that the showed group is the group n. Then, the form (?n), located inside the group n, is a recursive call to that group n
Concerning your problem, Daniel, the solution is the regex, below :
(^([^()\r\n])*(\(((?2)|(?3))*\))(?2)*\r?\n)+
You may use the PCRE_EXTENTED option (?x) to get the regex :
(?x) ( ^ ([^()\r\n])* ( \( ( (?2) | (?3) )* \) ) (?2)* \r?\n )+
These regexes look for any consecutive sequence of entire lines, with their End of Line character(s), whose each of them :
Is, of the general form, ....(.......).....
Contents well-balanced nested couples (), inside the upper-level block (....)
So, Daniel, if you leave the replace field empty, you’ll get, ONLY, the lines where the number of opening round brackets is different from the number of closing round brackets, or lines without any round bracket at all !
For instance, these regexes, above, don’t match any of these following lines :
abcdef
abc(def
a(b)def)ghi
a(bc(((d))ef)g
But they do match, in one go, the block of these seven following lines, with well-balanced couples of () :
abc(de)f
(a(bdef)ghi)
a(bc(((d))e)f)g
a()bc
((ab(cde((fgh)ij)kl))mno)pqr
ab(c(de(fgh(ijk))lm)((()))n()()op)qrs
In short :
The form (?2) is a NON recursive call to the sub-pattern [^()\r\n]
The form (?3) is a recursive call to the sub-pattern \( ( (?2) | (?3) )* \)
The anchor ^, at beginning and \r?\n, at the end, allow to cover an entire line, which can be repeated, due to the final + sign, applying to group 1
The opening and closing round brackets need to be escaped \( and \). Just notice that escaping round brackets, inside the class character [....], at the beginning of the regex, is not mandatory !
Inside the block \(....\), the regex looks for any sequence, even empty, of :
(?2) Characters
different from
round brackets and from
End of Line characters
OR
(?3)Nested other blocks of
round brackets
(....)
and so on…
I’ll give you any further information, about the recursion concept, if anyone needs to !
Best regards,
guy038
P.S.,
To end, I give you an other regex, with a recursive pattern (?2), which can match the general case of the string ....(.........)............(..)...(....)...........
So, this regex, below, matches the tallest sequence of characters, even on several lines, which contains as much as opening round brackets than closing round brackets, with well-nested and/or juxtaposed other blocs (....) :
([^()]*(\(([^()]|(?2))*\))[^()]*)+
With the PCRE_EXTENTED option (?x), we get the regex :
(?x) ( [^()]* ( \( ( [^()] | (?2) )* \) ) [^()]* )+
And, if you don’t think to use the group 1, in the replacement part, with the backreference \1, you may set group 1, as a non-capturing group, with the syntax ?:, in :
(?:[^()]*(\(([^()]|(?1))*\))[^()]*)+
(?x) (?: [^()]* ( \( ( [^()] | (?1) )* \) ) [^()]* )+
Of course, because of the first non-capturing group, the old recursive group 2 becomes the recursive group 1