Oh, yeah, forgot. Bit rushed right now.
For convenience's sake, instead of saying (chaindik|Chain dik|Chain d.i.k|etc.) I'm just going to say thingy.
Okay: match thingy so long as it doesn't appear inside an <a> entity. Well, a string is "inside" such an entity if, when reading forwards from it, an </a> is sighted before an <a or the end of the string (assuming that the string doesn't itself cut short in the middle of a link). This applies both to the <a> tag's attributes and to text between the <a> and </a> tags (you can't nest links). (It also applies to attributes of other tags in between, unfortunately - so if they contain the pattern we're looking for we're in trouble.)
That's inside though - we want outside. Basically, we want a pattern that will successfully match whenever it starts from a point outside a tag. In other words, we want to match any and all characters up to the next <a or the end of the string (whichever comes first), but only if it doesn't match </a> along the way.
To be brief, a pattern that does this is:
color=darkblue*(<a|$)[/color]
To dissect that:
color=darkblue[/color]
Is pretty self-explanatory - "<a or the end of the string".
color=darkblue[/color]
That's our assertion. Wherever we are right now, for a match to succeed, the next characters must not be </a>.
color=darkblue.[/color]
By preceding the usual "match any character" symbol by our assertion, we've ensured that we only match a character if it is not the start of an </a> tag. Just saying [<] instead of . won't work, because < could quite happily appear in many other situations as well, and we're quite happy for it to do so.
color=darkblue*[/color]
Zero or more occurrences. This pattern will match any string up to the first </a> string it sees (or the end of the string, whichever comes first) and stop there. The </a> is not included as part of the match (an assertion only a condition the match must satisfy - not part of the match itself).
color=darkblue*(<a|$)[/color]
And of course we want to keep matching until we find an <a.
Well, that's our pattern for matching strings that are outside tags -
if we're going to match anything, it must also satisfy this condition. Let's assert it - positively, this time because this condition Must be satisfied.
(?=((?!</a>).)*(<a|$))
And what is it we're matching? I've been calling it thingy. Sticking in the regexp delimiters and a couple of appropriate modifier characters:
#(thingy)(?=((?!</a>).)*(<a|$))#is
And the bit of text that matched thingy (and that is actually the only bit that is matched, because everything else is wrapped up in that ?= assertion) will be in \1, ready for use in the replacement text of a preg_replace().
There are some (rather brief) notes on the subject of assertions and other bits of PCRE syntax in the manual. Very small examples, don't really give a flavour of what they're good for.
(And I notice vBulletin has seen fit to insert some spruious spaces in there.)