There are a lot of tricky things you can do with regular expressions, but in the end you'll never cover every possibility and will still need some human moderation.
If using preg_ functions, you can use the assertions "\b" for a word boundary and "\B" for a non word boundary. To help with some of this. For example, if you only want to match on the word "bug" but not "firebug" or "buggy":
$text = preg_replace('/\bbug\b/i', '***', $text);
If you want to censor "dog" by itself or at the end of any word except "nogdog", you could do:
$text = "Dog is bad and so is pupdog, but NogDog is OK, doggy.";
$text = preg_replace('/\b(\w*)(?<!nog)dog\b/i', "$1***", $text);
echo $text;
/* Out put is:
*** is bad and so is pup***, but NogDog is OK, doggy.
*/