<?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" => '', #вырезаем "мягкий" перенос строки (­)
"\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;
}
?>