Пожалуйста, ознакомьтесь с этой статьей "clbuttic" (или для вашего случая cl [Censored] ic) перед выполнением замены строки без учета границ слова:
http://www.codinghorror.com/blog/2008/10/obscenity-filters-bad-idea-or-incredibly-intercoursing-bad-idea.html
Обновление
Очевидно, что не является надежным (см. Статью выше - этот подход очень легко обойти или создать ложные срабатывания ...) или оптимизировать (регулярные выражения должны быть кэшированы и скомпилированы), но следующее отфильтрует целые слова (нет "clbuttics") и простое множественное число слов:
const string CensoredText = "[Censored]";
const string PatternTemplate = @"\b({0})(s?)\b";
const RegexOptions Options = RegexOptions.IgnoreCase;
string[] badWords = new[] { "cranberrying", "chuffing", "ass" };
IEnumerable<Regex> badWordMatchers = badWords.
Select(x => new Regex(string.Format(PatternTemplate, x), Options));
string input = "I've had no cranberrying sleep for chuffing chuffings days -
the next door neighbour is playing classical music at full tilt!";
string output = badWordMatchers.
Aggregate(input, (current, matcher) => matcher.Replace(current, CensoredText));
Console.WriteLine(output);
Дает вывод:
У меня не было [цензурированного] сна в течение [цензурированных] [цензурированных] дней - сосед по соседству играет классическую музыку на полном ходу!
Обратите внимание, что «классический» не становится «cl [Censored] ical», поскольку целые слова сопоставляются с регулярным выражением.
Обновление 2
И чтобы продемонстрировать, как это (и в целом основные методы сопоставления строк и шаблонов) можно легко подорвать, см. Следующую строку:
«У меня не было клюквенного сна в течение нескольких дней - сосед по соседству играет классическую музыку на полном ходу!»
Я заменил "i" на турецкие строчные буквы "ı". По-прежнему выглядит довольно обидно!