Personally, if my regular expressions were approaching this level of complexity, I would just switch the whole operation to Perl. This one deals with an arbitrary number of open braces/parentheses/curly braces:
$ perl -ne '@open=/[\[({]/g; @close=/[)\]}]/g;
if($#close == $#open){s/(.+?)\.is/($1).is/} print' file
Or, more compact:
$ perl -pne 's/(.+?)\.is/($1).is/ if $#{/[\[({]/g} == $#{/[)\]}]/g}' file
Or more complete, this one can deal with cases like [} (but still fails on cases like )():
$ perl -pne '@osqb=/\[/g; @csqb=/\]/g;
@ocb=/\{/g; @ccb=/\}/g;
@op=/\(/g; @cp=/\)/g;
if($#osqb == $#csqb && $#ocb==$#ccb && $#op == $#cp){
s/(.+?)\.is/($1).is/
}' file
When run on your example, this will print
(this_thing).is 24
(that).is 50
(a[23]).is == 10
(a).is true
(this_thing).is 24
this_thing.is (24
((that).is 50
(a[23].is == 10
a.is ( true
(this_thing.is 24
a{.is true
this_thing{.is 24
a[.is true
this_thing[.is 24
###Explanation
Explanation
perl -ne: process the input file line by line (-n) and run the script given by-e.@open=/[\[({]/g;: find all opening glyphs and save the result in an array called@open.@close=/[)\]}]/g;: as above but for closing glyphs.if($#close == $#open): if the number of opening glyphs is equal to the number of closing glyphs (if, in other words there are hanging parentheses etc)...s/(.+?)\.is/($1).is/: ...then replace the shortest string that ends in.iswith itself enclosed within parentheses.- The last
printis outside the brackets and will be executed whether there was a substitution or not.