Sean,
I'll take the parts one at a time.
(?<![?:]) - You are correct that the '[?:]' part will match either a question mark or a colon.
The '(?<!' part is a negative lookbehind. This means that the regex engine will begin at its current point in the source text and look backwards, trying to match the characters. In this case it is looking to see if the character just before where it is up to is a '?' or a ':'. If it IS one of these, then it will return a 'fail' because it is a negative lookbehind. If the previous character is NOT one of these, then it will return a 'success'. The trick with lookaheads and lookbehinds is that the take part in a match but they don't move the 'current point' in the text - they only look.
With Perl, lookbehinds are supported but they must be of fixed length - in other words you can't have quantifiers like '+' and '*' in them etc.. In this case the lookbehind is always a single character long and so this is acceptable.
Therefore the total effect of this part of the pattern is to see if the preceeding character is a question mark or a colon.
As for the '^' representing 'not', this is true ONLY in a character class where it says that the character class represents all characters except those that are explicitly specified. Outside a character class, '^' means the start of a line or the whole text, depending on the setting of the 'multiline' option.
Therefore we can put the above together and look at your replacement sub-pattern of '([^?:])'. What this will do is to create a match grup (the outer parenthesis) that contains a single character class that will match and capture all characters that are not a question mark or a colon. This will work (except when the following text is actually at the start of the text/line) but it will include the non- colon/question-mark in your overall capture. When you come to do the replacement, the non- question mark/colon will be removed along with everything else wcih is NOT what you want.
I think you have got the next bit (the 'console\........' part) sorted OK.
\(("[^"]*"|[^)])*\)
We can start by stripping off the '\(' and '\)' from the beginning and the end - these simply match literal open and closing parentheses.
Whats left is a match group (the un-escaped parentheses) that contain two alternate sub-patterns.
"[^"]*" - match a qouble-quote and then match as many characters as possible as long as they are not a double-quote and then match a double-quote. This is a fairly standard way of handling a quoted string and skipping over everything between the double-quotes - especially characters (such as a close parenthesis) that could cause problems in the curcumstances.
[^)] - match any character that is not a close parenthesis.
In this situation you are looking for an open parenthsis (already dealt with) and then skip everything until you get to the next close parenthesis but ignoring any close parenthesis that may occur within a double-quoted string. As the regex engine starts this part of the pattern, it is positioned just after the open parenthesis. Lets say we find a double-quote: the first alternate will match and do we skip to the next double-quote that ends the string - treating everything in between as a single 'item'. We heve then satisfied this alternate path and so we have satisfied the whole match group. Next we get to the '*' quantifier and so we start over again.
Lets say the next character is neither a double-quote or the close parenthesis (I think this occurred in part of your example text). The regex engine will be positioned just after the last double-quote found above and just before this 'other' character. The alternate patterns are searching in the order they are specified and so the engine will check to see if it is a double-quote - whichi it isn't and so it will try the second alternative. The 2nd alternative is a character class that will match anything that is not a close parenthesis. In this case we will get a match and so the match group as a whole is again satisfied.
While we are here, lets immagine that the alternate patterns are swapped around and see what would happen if the next character was a double-quote. THe first alternative is now the check for anything that is not a close-parenthesis and so the double-quote will match and the whole match group will succeed. However we have just matched the start of a quoted string and so we have missed the chance to detect it. This demonstrates the general rule that alternates should be specified in the most-specified to the most general order.
OK, lets now imagine that we have matched everything up to and including the character before the close parenthesis and we are at the end of the match group. We are still working under the influence of the '*' quantifier and so we start again. Now the next source character will be the close parenthesis and we try to match it with the first of the alternatives (the double-quote) and so this will not match: we skip to the econd alternative. This won't match either as is IS a close parenthesis and so the match group as a whole will fail.
However, the '*' will match 0 or more instances of the preceding item (our match group) and so everything is still OK. if we have matched something, then we have a match of more than 0 and so the overall effect is 'success'. If the source text was "()" then we will hve matched 0 times, but that is still OK and so we move on.
We then match with the literal close parenthesis at the end of this part of the pattern and so all is well.
As for the syntax errors, I don't know enough of Perl to help you. However, experience with regex syntax error normally show up in one of 2 forms: those form the language parser when the pattern has not been presented in a form that it can process (e.g. you have to pass a string to the PCRE functions amd you have to play with the pattern if it contains double-quotes that the langauge parser will trip up on), and then the resulting regex pattern is not understood by the regex engine itself. Normally the error messages will give you enough of a context to tell which is which.
Susan