<?php



/**

 * Функция пытается определить наличие мата (нецензурных, матерных слов) в html-тексте в кодировке UTF-8.

 * Возвращает false, если мат не обнаружен, иначе фрагмент текста с матерным словом.

 *

 * Алгоритм достаточно надежен и быстр, в т.ч. на больших объемах данных.

 * Метод обнаружения мата основывается на корнях и предлогах русского языка, а не на словаре.

 * Слова "лох", "хер", "залупа", "сука" матерными словами не считаются (см. словарь Даля)

 *

 * http://www.google.com/search?q=%F2%EE%EB%EA%EE%E2%FB%E9%20%F1%EB%EE%E2%E0%F0%FC%20%F0%F3%F1%F1%EA%EE%E3%EE%20%EC%E0%F2%E0&ie=cp1251&oe=UTF-8

 * http://www.awd.ru/dic.htm (Толковый словарь русского мата.)

 *

 * @param    string               $s         строка в кодировке UTF-8

 * @param    string               $delta     ширина найденного фрагмента в словах

 *                                           (кол-во слов от матного слова слева и справа, максимально 10)

 * @param    string               $continue  строка, которая будет вставлена в начале в конце фрагмента

 * @return   mixed(false/string)

 * @author   Nasibullin Rinat <n a s i b u l l i n  at starlink ru>

 * @charset  UTF-8

 * @version  3.1.0-beta

 * @since    2005

 * @dependencies strip_tags_smart(), utf8_html_entity_decode(), utf8_convert_case()

 */

function censure($s, $delta = 3, $continue = "\xe2\x80\xa6")

{

    #предлоги русского языка:

    #[всуо]|

    #по|за|на|об|до|от|вы|вс|вз|из|ис|

    #под|про|при|над|низ|раз|рас|воз|вос|

    #пооб|повы|пона|поза|недо|пере|одно|

    #полуза|произ|пораз|много|

    static $pretext = array(

        #1

        '[уyоo]_?        (?=[еёeхx])',        #у, о   (уебать, охуеть)

        '[вvbсc]_?       (?=[хпбмгжxpmgj])',  #в, с   (впиздячить, схуярить)

        '[вvbсc]_?[ъь]_? (?=[еёe])',          #въ, съ (съебаться, въебать)

        'ё_?             (?=[бb])',           #ё      (ёбля)

        #2

        '[вvb]_?[ыi]_?',      #вы

        '[зz3]_?[аa]_?',      #за

        '[нnh]_?[аaеeиi]_?',  #на, не, ни

        '[вvb]_?[сc]_?          (?=[хпбмгжxpmgj])',  #вс (вспизднуть)

        '[оo]_?[тtбb]_?         (?=[хпбмгжxpmgj])',  #от, об

        '[оo]_?[тtбb]_?[ъь]_?   (?=[еёe])',          #отъ, объ

        '[иiвvb]_?[зz3]_?       (?=[хпбмгжxpmgj])',  #[ив]з

        '[иiвvb]_?[зz3]_?[ъь]_? (?=[еёe])',          #[ив]зъ

        '[иi]_?[сc]_?           (?=[хпбмгжxpmgj])',  #ис

        '[пpдdg]_?[оo]_? (?> [бb]_?         (?=[хпбмгжxpmgj])

                           | [бb]_?  [ъь]_? (?=[еёe])

                           | [зz3]_? [аa] _?

                         )?',  #по, до, пообъ, дообъ, поза, доза (двойные символы вырезаются!)

        #3

        '[пp]_?[рr]_?[оoиi]_?',  #пр[ои]

        '[зz3]_?[лl]_?[оo]_?',   #зло (злоебучая)

        '[нnh]_?[аa]_?[дdg]_?         (?=[хпбмгжxpmgj])',  #над

        '[нnh]_?[аa]_?[дdg]_?[ъь]_?   (?=[еёe])',          #надъ

        '[пp]_?[оo]_?[дdg]_?          (?=[хпбмгжxpmgj])',  #под

        '[пp]_?[оo]_?[дdg]_?[ъь]_?    (?=[еёe])',          #подъ

        '[рr]_?[аa]_?[зz3сc]_?        (?=[хпбмгжxpmgj])',  #ра[зс]

        '[рr]_?[аa]_?[зz3сc]_?[ъь]_?  (?=[еёe])',          #ра[зс]ъ

        '[вvb]_?[оo]_?[зz3сc]_?       (?=[хпбмгжxpmgj])',  #во[зс]

        '[вvb]_?[оo]_?[зz3сc]_?[ъь]_? (?=[еёe])',          #во[зс]ъ

        #4

        '[нnh]_?[еe]_?[дdg]_?[оo]_?',    #недо

        '[пp]_?[еe]_?[рr]_?[еe]_?',      #пере

        '[oо]_?[дdg]_?[нnh]_?[оo]_?',    #одно

        '[кk]_?[oо]_?[нnh]_?[оo]_?',     #коно (коноебиться)

        '[мm]_?[уy]_?[дdg]_?[оoаa]_?',   #муд[оа] (мудаёб)

        '[oо]_?[сc]_?[тt]_?[оo]_?',      #осто (остопиздело)

        '[дdg]_?[уy]_?[рpr]_?[оoаa]_?',  #дур[оа]

        '[хx]_?[уy]_?[дdg]_?[оoаa]_?',   #худ[оа] (худоебина)

        #5

        '[мm]_?[нnh]_?[оo]_?[гg]_?[оo]_?',    #много

        '[мm]_?[оo]_?[рpr]_?[дdg]_?[оoаa]_?', #морд[оа]

        '[мm]_?[оo]_?[зz3]_?[гg]_?[оoаa]_?',  #мозг[оа]

        '[дdg]_?[оo]_?[лl]_?[бb6]_?[оoаa]_?', #долб[оа]

    );



    static $badwords = array(

        #Слово на букву Х

        '(?<=[_\d]) {RE_PRETEXT}?

         [hхx]_?[уyu]_?[йiеeёяюju]     #хуй, хуя, хую, хуем, хуёвый

         #исключения:

         (?<! _hue(?=_)    #HUE    -- цветовая палитра

            | _hue(?=so_)  #hueso  -- испанское слово

            | _хуе(?=дин)  #Хуедин -- город в Румынии

         )',



        #Слово на букву П

        '(?<=[_\d]) {RE_PRETEXT}?

         [пp]_?[иi]_?[зz3]_?[дd]_?[:vowel:]',  #пизда, пизде, пиздёж, пизду, пиздюлина, пиздобол, опиздинеть, пиздых



        #Слово на букву Е

        '(?<=[_\d]) {RE_PRETEXT}?

         [eеё]_? (?<!не[её]_) [бb6]_?(?: [уyиi]_                       #ебу, еби

                                       | [ыиiоoaаеeёуy]_?[:consonant:] #ебут, ебать, ебись, ебёт, поеботина, выебываться, ёбарь

                                       | [лl][оoаaыиi]                 #ебло, ебла, ебливая, еблись, еблысь

                                       | [нn]_?[уy]                    #ёбнул, ёбнутый

                                       | [кk]_?[аa]                    #взъёбка

                                      )',

        '(?<=[_\d]) {RE_PRETEXT}

         (?<=[^_\d][^_\d]|[^_\d]_[^_\d]_) [eеё]_?[бb6] (?:_|_?[аa]_?[^_\d])',  #долбоёб, дураёб, изъёб, заёб, разъебай



        #Слово на букву Б

        '(?<=[_\d]) {RE_PRETEXT}?

         [бb6]_?[лl]_?(?:я|ya)(?: _       #бля

                                | _?[тд]  #блять, бляди

                              )',



        #ПИДОР

        '(?<=[_\d]) [пp]_?[иieе]_?[дdg]_?[eеaаoо]_?[rpр]',  #п[ие]д[оеа]р



        #МУДАК

        '(?<=[_\d]) [мm]_?[уy]_?[дdg]_?[аa]',  #муда



        #ЖОПА

        '(?<=[_\d]) [zж]_?h?_?[оo]_?[pп]_?[aаyуыiеeoо]',  #жоп[ауыео]



        #МАНДА

        #исключения: город Мандалай, округ Мандаль, индейский народ Мандан, фамилия Мандель

        '(?<=[_\d]) [мm]_?[аa]_?[нnh]_?[дdg]_?[aаyуыiеeoо](?<! манда(?=[лн])|манде(?=ль ))', #манд[ауыео]



        #ГОВНО

        '(?<=[_\d]) [гg]_?[оo]_?[вvb]_?[нnh]_?[оoаaяеeyу]', #говн[оаяеу]



        #FUCK

        '(?<=[_\d]) f_?u_?[cс]_?k',  #fuck



        /*

        #ЛОХ

        ' л_?[оo]_?[хx]',



        #СУКА

        '[^р]_?[scс]_?[yуu]_?[kк]_?[aаiи]', #сука (кроме слова "барсука" - это животное-грызун)

        '[^р]_?[scс]_?[yуu]_?[4ч]_?[кk]',   #сучк(и) (кроме слова "барсучка")



        #ХЕР

        ' {RE_PRETEXT}?[хxh]_?[еe]_?[рpr](_?[нnh]_?(я|ya)| )', #{RE_PRETEXT}хер(ня)



        #ЗАЛУПА

        ' [зz3]_?[аa]_?[лl]_?[уy]_?[пp]_?[аa]',

        */

    );



    static $re_trans = array(

        '_'             => '\x20',                               #пробел

        '[:vowel:]'     => '[аеиоуыэюяёaeioyu]',                 #гласные буквы

        '[:consonant:]' => '[^аеиоуыэюяёaeioyu\x20\d]',          #согласные буквы

    );

    $re_badwords = str_replace('{RE_PRETEXT}',

                               '(?>' . implode('|', $pretext) . ')',

                               '~' . implode('|', $badwords) . '~sxu');

    $re_badwords = strtr($re_badwords, $re_trans);



    #вырезаем все лишнее

    #скрипты не вырезаем, т.к. м.б. обходной маневр на с кодом на javascript:

    #<script>document.write('сло'+'во')</script>

    #хотя давать пользователю возможность использовать код на javascript нехорошо

    if (! function_exists('strip_tags_smart')) include_once H.'sys/inc/strip_tags_smart.php'; #оптимизация скорости include_once

    $s = strip_tags_smart($s, null, true, array('comment', 'style', 'map', 'frameset', 'object', 'applet'));



    #заменяем html-сущности в "чистый" UTF-8

    if (! function_exists('utf8_html_entity_decode')) include_once H.'sys/inc/utf8_html_entity_decode.php'; #оптимизация скорости include_once

    $s = utf8_html_entity_decode($s, $is_htmlspecialchars = true);



    if (! function_exists('utf8_convert_case')) include_once H.'sys/inc/utf8_convert_case.php'; #оптимизация скорости include_once

    $s = utf8_convert_case($s, CASE_LOWER);



    static $trans = array(

        "\xc2\xad" => '',   #вырезаем "мягкий" перенос строки (&shy;)

        "\xcc\x81" => '',   #вырезаем знак ударения (U+0301 «combining acute accent»)

        '/\\'      => 'л',  #Б/\Я

        '/|'       => 'л',  #Б/|Я

        "\xd0\xb5\xd0\xb5" => "\xd0\xb5\xd1\x91",  #ее => её

    );

    $s = strtr($s, $trans);



    #получаем в массив только буквы и цифры

    #"с_л@о#во,с\xc2\xa7лово.Слово" -> "слово слово слово"

    preg_match_all('/(?> \xd0[\xb0-\xbf]|\xd1[\x80-\x8f\x91]  #[а-я]

                      |  [a-z\d]+

                      )+

                    /sx', $s, $m);

    $s = ' ' . implode(' ', $m[0]) . ' ';



    #убираем все повторяющиеся символы

    #"сллоооовоо   слово" -> "слово слово"

    $s = preg_replace('/(  [\xd0\xd1][\x80-\xbf]  #оптимизированное [а-я]

                         | [a-z\d]

                         ) \\1+

                       /sx', '$1', $s);

    #d($s);

    if (preg_match($re_badwords, $s, $m, PREG_OFFSET_CAPTURE))

    {

        list($word, $offset) = $m[0];

        $s1 = substr($s, 0, $offset);

        $s2 = substr($s, $offset + strlen($word));

        $delta = intval($delta);

        if ($delta < 1 || $delta > 10) $delta = 3;

        preg_match('/  (?> \x20 (?>[\xd0\xd1][\x80-\xbf]|[a-z\d]+)+ ){1,' . $delta . '}

                       \x20?

                    $/sx', $s1, $m1);

        preg_match('/^ (?>[\xd0\xd1][\x80-\xbf]|[a-z\d]+)*  #окончание

                       \x20?

                       (?> (?>[\xd0\xd1][\x80-\xbf]|[a-z\d]+)+ \x20 ){1,' . $delta . '}

                    /sx', $s2, $m2);

        $fragment = (ltrim(@$m1[0]) !== ltrim($s1) ? $continue : '') .

                    trim(@$m1[0] . '[' . trim($word) . ']' . @$m2[0]) .

                    (rtrim(@$m2[0]) !== rtrim($s2) ? $continue : '');

        return $fragment;

    }

    return false;

}



?>

