Фильтр мата

Сегодня я хотел бы затронуть такую тему, как фильтрование нецензурных выражений, или попросту, мата. Понятно, что если Вы владеете каким-нибудь форумом или блогом (сайтом, где можно оставлять сообщения), то как владельцу, Вам будет неприятно, если там будут материться.

Решением этой проблемы может являться конечно и модерация, но представьте себе, что ресурс довольно крупный и в день валятся сотни сообщений. Тут не до модерации :)

Другим решением может быть фильтр мата. Сразу говорю, что такой фильтр идеальным не сделаешь, потому что изобретательность человека не имеет границ. Идеальный фильтр мата - сам человек, или его замена - искусственный интеллект, который, к сожалению (а может и к счастью), еще не придумали.

Поэтому здесь мы рассмотрим наиболее часто используемые и несложные методики фильтрования нежелательных слов.

Итак, какие я выделяю способы:

  1. Регулярные выражения
  2. Список слов (самый примитивный способ)
  3. Функция similar_text совместно с фильтрованием ненужных знаков в слове

Регулярные выражения

Суть этого метода в том, чтобы составить такое регулярное выражение, чтобы оно смогло поймать как можно больше матных слов. Прежде чем писать самому фильтр на основе регулярных выражений, я поискал готовые реализации в нете и нашел две:

diktator_antimat v1.1_alfa
и
Anti Mate PHP Class

Первая реализация довольно небольшая и я сразу приведу ее код здесь:

<!--?php <br ?--> ##################################################################
# Скрипт diktator_antimat v1.1_alfa #
# Автор Дмитрий Перов method_05@list.ru #
# #
# Скрипт Распостраняется бесплатно , ссылка #
# На Автора - по желанию...(знаю о чём вы сейчас подумали=)) #
# #
# Обработал этим скриптом большой объём текста, вот #
# слова которые распознаются как маты:грёбля, грёбаный, глухую ,#
# ХЛЕБАЛО,ХЛЕБАЛЬНИК,хулиган... #
# #
# Сложно просмотреть и предусмотреть Всё... #
# Так что о багах - мне на мыло... #
# #
# Всякого рода Модификации скрипта без согласования #
# с Автором запрещены! #
# Удачи! #
##################################################################

@setlocale(LC_ALL, array ('ru_RU.CP1251', 'rus_RUS.1251'));

$pattern = "/\w{0,5}[хx]([хx\s\!@#\$%\^&*+-\|\/]{0,6})[уy]([уy\s\!@#\$%\^&*+-\|\/]{0,6})[ёiлeеюийя]\w{0,7}|\w{0,6}[пp]([пp\s\!@#\$%\^&*+-\|\/]{0,6})[iие]([iие\s\!@#\$%\^&*+-\|\/]{0,6})[3зс]([3зс\s\!@#\$%\^&*+-\|\/]{0,6})[дd]\w{0,10}|[сcs][уy]([уy\!@#\$%\^&*+-\|\/]{0,6})[4чkк]\w{1,3}|\w{0,4}[bб]([bб\s\!@#\$%\^&*+-\|\/]{0,6})[lл]([lл\s\!@#\$%\^&*+-\|\/]{0,6})[yя]\w{0,10}|\w{0,8}[её][bб][лске@eыиаa][наи@йвл]\w{0,8}|\w{0,4}[еe]([еe\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[uу]([uу\s\!@#\$%\^&*+-\|\/]{0,6})[н4ч]\w{0,4}|\w{0,4}[еeё]([еeё\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[нn]([нn\s\!@#\$%\^&*+-\|\/]{0,6})[уy]\w{0,4}|\w{0,4}[еe]([еe\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[оoаa@]([оoаa@\s\!@#\$%\^&*+-\|\/]{0,6})[тnнt]\w{0,4}|\w{0,10}[ё]([ё\!@#\$%\^&*+-\|\/]{0,6})[б]\w{0,6}|\w{0,4}[pп]([pп\s\!@#\$%\^&*+-\|\/]{0,6})[иeеi]([иeеi\s\!@#\$%\^&*+-\|\/]{0,6})[дd]([дd\s\!@#\$%\^&*+-\|\/]{0,6})[oоаa@еeиi]([oоаa@еeиi\s\!@#\$%\^&*+-\|\/]{0,6})[рr]\w{0,12}/i";

$replacement = "Цензура";

$text = preg_replace($pattern, $replacement, $text);

/*
$pattern - то, что ищем
$replacement - то, чем заменяем
$text - то, что обрабатываем
*/

?&gt;

Проверив этот скрипт, я пришел к выводу, что он заменяет большинство матерных слов нашего русского языка, но не учитывает новые формы. Например, «сцуко» вместо «сука». Поэтому пишите автору на мыло :) Также минусом этого скрипта я вижу неумение искать русские слова, написанные английскими буквами (это называется транслитерацией, если кто не знает).

Само регулярное выражение конечно впечатляет :)

Это конечно хорошо, но стоит вставить в слово левые знаки, как фильтр запросто обходится: сука = с.у.к.а, с-у-к-а, су|

А вот и реализация Anti Mate PHP Class:

/********************************************/
/*Welcome to Anti Mate PHP Class source-code!*/
/*The Anti Mate PHP Class and its functions, contexture are copyrighted by s1ayer [www.spg.arbse.net]*/
/*Current file: anti_mate.php*/
/*Optimized for PHP 4.3.6, Apache 1.3.27*/
/********************************************/

setlocale (LC_ALL, "ru_RU.CP1251");
/**/
class anti_mate {
//latin equivalents for russian letters
var $let_matches = array (
"a" =&gt; "а",
"c" =&gt; "с",
"e" =&gt; "е",
"k" =&gt; "к",
"m" =&gt; "м",
"o" =&gt; "о",
"x" =&gt; "х",
"y" =&gt; "у",
"ё" =&gt; "е"
);
//bad words array. Regexp's symbols are readable !
var $bad_words = array (".*ху(й|и|я|е|л(и|е)).*", ".*пи(з|с)д.*", "бля.*", ".*бля(д|т|ц).*", "(с|сц)ук(а|о|и).*", "еб.*", ".*уеб.*", "заеб.*", ".*еб(а|и)(н|с|щ|ц).*", ".*ебу(ч|щ).*", ".*пид(о|е)р.*", ".*хер.*", "г(а|о)ндон", ".*залуп.*");

function rand_replace (){
$output = " <span style="color: red;">[censored]</span> ";
return $output;
}
function filter ($string){
$counter = 0;
$elems = explode (" ", $string); //here we explode string to words
$count_elems = count($elems);
for ($i=0; $i {
$blocked = 0;
/*formating word...*/
$str_rep = eregi_replace ("[^a-zA-Zа-яА-Яё]", "", strtolower($elems[$i]));
for ($j=0; $j {
foreach ($this-&gt;let_matches as $key =&gt; $value)
{
if ($str_rep[$j] == $key)
$str_rep[$j] = $value;

}
}
/*done*/

/*here we are trying to find bad word*/
/*match in the special array*/
for ($k=0; $kbad_words); $k++)
{
if (ereg("\*$", $this-&gt;bad_words[$k]))
{
if (ereg("^".$this-&gt;bad_words[$k], $str_rep))
{
$elems[$i] = $this-&gt;rand_replace();
$blocked = 1;
$counter++;
break;
}

}
if ($str_rep == $this-&gt;bad_words[$k]){
$elems[$i] = $this-&gt;rand_replace();
$blocked = 1;
$counter++;
break;
}

}
}
if ($counter != 0)
$string = implode (" ", $elems); //here we implode words in the whole string
return $string;
}
}
/**/
?&gt;

Я его проверил вот так:

$anti_mate = new anti_mate();
echo $anti_mate->filter(‘бля, пошли все на. сцуки’);

При этом скрипт вывел: [censored] пошли все на. [censored]

Вглядываясь в код, видим, что есть возможность проверки английских эквивалентов русских слов, но довольно слабая. Ведь одну и ту же русскую букву можно по-разному протранслитерировать.

Например, буква х - }{, )(, ][, h, ch, x …

Конечно, в рассмотренных скриптах куча недостатков имеется, потому что все варианты не предусмотреть. Если будете использовать - рекомендую использовать их совместно.

Список слов (самый примитивный способ)

Этот способ настолько примитивен и наивен, что вряд ли кто-то будет его использовать. Но все же он - это первое, что приходит в голову, когда думаешь о фильтровании нежелательных слов. Суть способа в том, что есть массив нежелательных слов, и есть строка, в которой их нужно заменить, например, на [censored]. Просто пробегаем по массиву и ищем при каждой итерации очередное слово из массива в строке и заменяем его, если оно найдено.

Функция similar_text

Интересная функция в PHP. Она сравнивает две строки и возвращает степень их похожести в процентах. Пример:

similar_text(‘сука’, ‘су|// $percent ~ 67 %.

Можно ее использовать, но опять же есть недостатки. Можно принять какое-нибудь вполне нормальное слово за матное. Поэтому тут нужно быть осторожными с процентами. Брать высокий процент - значит отсеивать множество ложных вариантов, но в то же время снижать вероятность правильности нахождения матных слов. Брать низкий процент - наоборот, ложных вариантов много, но зато найдет больше матных слов.

Тут как с антивирусом, у которого есть возможность эвристического анализа. Он может принять совершенно безвредную программу за вирус, если ему вдруг покажется, что она производит, на его взгляд, потенциально-опасные действия.

Поэтому нужно подбирать разумный процент (я бы выбрал, например, 65), но в то же время перед проверкой каждого слова очищать его от лишних знаков препинания (для случаев c.,у.,к.,а, например).

Кстати, есть еще функция levenshtein - вычисляет расстояние Левенштейна между двумя строками длиной не более 255 символов. Расстояние Левенштейна - это минимальное количество вставок, замен и удалений символов, чтобы преобразовать одну строку к другой. Т.е. чем меньше возвращенное этой функцией число, тем более похожи сравниваемые слова.

Итоги

Надеюсь, эта статья дала Вам повод для размышления над собственным фильтром мата, если собираетесь писать такой. Я рекомендовал бы использовать все три метода, которые я описал, но с добавлением чего-то оригинального с Вашей стороны. А вообще, я думаю, понятно, что фильтр нежелательных слов - довольно сложная штука и тут в идеале спасет только искусственный интеллект, или сам человек, что приближает нас все-таки к модерации сообщений.





Читайте также:



21 Ответов на “Фильтр мата”

  1. Идеально должно быть что-то вроде обучающегося алгоритма, типа как фильтр спама по Байесу.

    То есть, как минимум, нужен лог произведенных замен в которых модератор проверяет не заменилось ли что лишнего, и смотрит выдачу не пропустило ли что, что нужно было отфильтровать. Чтобы не просматривать все подряд можно использовать левенштейна, например, для формирования списка “подозрительных” постов.

    В общем полная фильтрация мата задача далеко не тривиальная, как=то давно пришел к выводу, что проще пропускать слова по словарю, но увы, грамотность в постах страдает :(

  2. […] Подсветка программного кода в постах (для WordPress) Фильтр мата Плагин - подсказка по выделенному […]

  3. Что то неполучается на блог поставить себе этот фильр ошибочку выдает

  4. novice

    2cymkin: В чем именно ошибка?

  5. Вроде как и полезный фильтр. А часто у вас в блогах выражаются непечатными выражениями? Если блог по не развлекательной тематике - редко ведь такое встречается. Но вообще конечно полезно. Спасибо.

  6. novice

    Да нет, пока не выражались :)

  7. А как сей механизм реализуется в различных движках форумов?

  8. Michael

    Лучше всего совместить “самый примитивный способ” со способом similar_text.

    Выглядеть будет так, сначала пробегаем по тексту similar_text фильтром фильтруя самое основное, затем фильтр по словарю, фильтрует особо сложные в написании ругательства.

    Плюс к этому делаем возможность модератору, например через AJAX, пополнять словаря. И еще хорошо бы добавить ссылку для пользователей “Пожаловаться на мат”. Таким способом можно свести мат на минимум.

  9. Michael

    А еще забыл нужен словарь исключений, что бы отображать слова похожие на мат но не матерные

  10. Отличная статья!

  11. Интересная статья.
    Проще всего, конечно, использовать “самый примитивный способ” - забить в базу все словоформы, а проверка на уровне sql делается в разу быстрее, чем на уровне язык php. Один минус - базу слов надо постоянно расширять. Вот предложение - что если сделать такую базу доступной для редактирования всеми? Типа Википедии… И тогда при проверке сервер бы обращался к этой постоянно обновляемой базе… Эх, мечты, мечты :)

    P.S. А Самообучающийся алгоритм - это утопия :)

  12. Вячеслав

    ИМХО сам подход порочный - программа правит сообщения человека. Человек умный а программа тупая, потому человек во первых всегда обдурит программу, а во вторых программа иногда правит неправильно. Терпеть не могу когда на форуме какой-либо тупой скрипт заставляет писать вместо “два рубля” - “два руblya” или “два руbля” или “два ру.б.л.я”, получается что вместо нормального, приличного слова, мне приходится материться (кстати извиняюсь что и тут приходится, но это же пример тут не обойдёшься без этого). Т.е. эффект от применения программы получается обратный.
    Помоему гораздо лучше отдать функции цензора модератору, но снабдить его при этом скриптом, который будет искать мат в сообщениях, а функции правки и “раздачи слонов” предоставить человеку а не тупой машине. Тем более что мат иногда бывает уместен и подходить к нему слишком формально нельзя.

  13. ereg уже не используется((

  14. олег

    у меня есть проблемка в обратном. нужно из кучи сообщений ну скажем около нескольких милиардов вытащить наиболее схожие к ключевым словам. на пример по словам панк рок музыка нужно вытащить из базы и пределить как наибелее схожие сообшения типа “наше рок движение воглавляется …” или ” наша группа появилась … ” предпологается что сообщения дудут длинными.
    никто не знает как именно реализовать такой код

  15. Андрей

    cцуко пи@дец

  16. нуну

    кто захочет тот ругнется
    С
    Утра
    Курица
    Аскетичная
    =)

  17. фара

    да нее ребят тут пэг мачт не поможет нада использовать массивчик не малый чтоб защитится от мата
    вставить туда все виды слов, искать новые виды мата (написания) вот и всё

  18. VK

    Список матершинных слов можно взять из списка запрещенных доменов зоны .рф:
    Но там надо что-то убирать, что-то добавлять.

  19. Yura

    Привет, как можно расшифровать ваш антимат и отредаткировать, при цитировании пользователя “Nataly пишет:” он в место этого просто пишет “Цензура” тоесть всю фразу глушит.

    У меня стоит эта часть:if ($antimat==TRUE) { // АНТИМАТ$pattern=”/\w{0,5}[хx]([хx\s\!@#\$%\^&*+-\|\/]{0,6})[уy]([уy\s\!@#\$%\^&*+-\|\/]{0,6})[ёiлeеюийя]\w{0,7}|\w{0,6}[пp]([пp\s\!@#\$%\^&*+-\|\/]{0,6})[iие]([iие\s\!@#\$%\^&*+-\|\/]{0,6})[3зс]([3зс\s\!@#\$%\^&*+-\|\/]{0,6})[дd]\w{0,10}|[сcs][уy]([уy\!@#\$%\^&*+-\|\/]{0,6})[4чkк]\w{1,3}|\w{0,4}[bб]([bб\s\!@#\$%\^&*+-\|\/]{0,6})[lл]([lл\s\!@#\$%\^&*+-\|\/]{0,6})[yя]\w{0,10}|\w{0,8}[её][bб][лске@eыиаa][наи@йвл]\w{0,8}|\w{0,4}[еe]([еe\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[uу]([uу\s\!@#\$%\^&*+-\|\/]{0,6})[н4ч]\w{0,4}|\w{0,4}[еeё]([еeё\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[нn]([нn\s\!@#\$%\^&*+-\|\/]{0,6})[уy]\w{0,4}|\w{0,4}[еe]([еe\s\!@#\$%\^&*+-\|\/]{0,6})[бb]([бb\s\!@#\$%\^&*+-\|\/]{0,6})[оoаa@]([оoаa@\s\!@#\$%\^&*+-\|\/]{0,6})[тnнt]\w{0,4}|\w{0,10}[ё]([ё\!@#\$%\^&*+-\|\/]{0,6})[б]\w{0,6}|\w{0,4}[pп]([pп\s\!@#\$%\^&*+-\|\/]{0,6})[иeеi]([иeеi\s\!@#\$%\^&*+-\|\/]{0,6})[дd]([дd\s\!@#\$%\^&*+-\|\/]{0,6})[oоаa@еeиi]([oоаa@еeиi\s\!@#\$%\^&*+-\|\/]{0,6})[рr]\w{0,12}/i”;$msg=preg_replace(“$pattern”,”Цензура“,$msg); }

  20. Yura

    А где ответ?

  21. Yura

    Ну и для чего держать эти глупые коменты, если не хочешь отвечать? Удалю твой сайт из закладок и иди на все четыре стороны.


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map