Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Тексты > Фильтр слов


Автор: Gold Dragon 30.1.2006, 11:07
Допустим есть гостевая книга. Сообщения оставляются без предварительной модерации. Есть список слов (мат и т.п.) которые нужно находить в сообщении и заменять

Вопрос:
- как грамотнее организовать проверку и замену? И главное, какие функции быстреке будут работать?

Автор: Mal Hack 30.1.2006, 13:28
Зависит от кол-ва слов и сложности правил...
В принципе и preg-replace() - 1 раз можно прогнать.

Автор: AztEK 30.1.2006, 14:17
А в идеале ещё и заменять слова, где скажем вместо русских букв используются латинские со схожим написанием.
Тут, наверное, стоит все схожие символы ложить в массив и прегать по массиву.
Правда не знаю насчёт скорости...

Автор: Gold Dragon 30.1.2006, 14:25
Mal Hack
почитал документацию и не совсем понял как это использовать

вот например нужно в сообщении делать следующие замещения
- aaa на ббб
- 1234 на 4321
- ёй на юй

а код типа такого

Код

$a = array ("ааа","1234","ёй");
$b = array ("ббб","4321","юй");
$str = "Строка в которой нужно искать и заменять";
$itog = preg_replace ($a, $b, $str);


так чтоли?

Автор: AntonioBanderaz 30.1.2006, 15:59
Цитата(Gold Dragon @ 30.1.2006, 14:25 Найти цитируемый пост)

так чтоли?

Это вроде str_replace
В преге регульки

Автор: BIG BROTHER 30.1.2006, 17:19
быстрее всего будет работать str_replace (т.е. обычная замена без регулярных выражений)
НО правильней ИМХО делать так: в базе хранить корни слов - матов и смотреть в тексте именно эти корни. При нахождении корня заменять все слово в котором этот корень есть (т.е. от пробела до пробела)

Но конечно на 100 уберечся нельзя например вот 2 слова: хорошо и xopoшo - визуально разницы вообще никакой а во втором слове буквы Х О и P- латинские икс, о и пе. да и после каждой буквы пробелов могут понаставить. В идеале конечно нужно все жестко модерировать и карать карой небесной нарушителей smile

Автор: AztEK 30.1.2006, 17:45
BIG BROTHER корни - не дело. Будет резать безобидные слова типа "застрахуйте"

Автор: Mal Hack 30.1.2006, 18:29
Gold Dragon, если так, то:
Код
<?php
// Provides: Hll Wrld f PHP
$vowels = array("a", "e", "i", "o", "u", "A", "E", "I", "O", "U");
$onlyconsonants = str_replace($vowels, "", "Hello World of PHP");

// Provides: You should eat pizza, beer, and ice cream every day
$phrase  = "You should eat fruits, vegetables, and fiber every day.";
$healthy = array("fruits", "vegetables", "fiber");
$yummy   = array("pizza", "beer", "ice cream");

$newphrase = str_replace($healthy, $yummy, $phrase);
?>

Если 5 юзаешь, то str_ireplace

Автор: Gold Dragon 31.1.2006, 11:06
BIG BROTHER
наверное всё таки нужна регулярка, т.к. в базе лежат слова, а их надо проверять на наличие не алфавитного знака в начале и в конце. Например, слово "устой" не должно попасть в "плохие" слова по маске "сто", а ".сто" должно попасть. Как мне это сделать регулярными выражениями?

Всем спасибо за пояснение к str_replace. Но как мне совместить это с базой? Или проще это хранить в переменной(Array) в каком-нибудь "языковом" файле? Если в базе, то наверное нужно будет всё равно в массив перегонять?


BIG BROTHER
само сабой, нет 100% защиты и нужна модерация, но я же не могу модерить постоянно online, вот и нужна какая-то элементарная защита пока модератор кушает пончики smile
Добавлено @ 11:07

я юзаю 5-ку

Автор: BIG BROTHER 31.1.2006, 22:27
Из базы не сложно перегнать в массив и прогнать str_replace и заменять на что-то вроде [censored] smile

Автор: Gold Dragon 1.2.2006, 11:48
BIG BROTHER
Цитата(Gold Dragon @ 31.1.2006, 11:06 Найти цитируемый пост)

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


Автор: Mal Hack 1.2.2006, 13:38
Gold Dragon
Код

$a = array ("ааа","1234","ёй");
$b = array ("ббб","4321","юй");
$str = "Строка в которой нужно искать и заменять";
$itog = preg_replace ("#(\s\.\-\+\=)(".implode($a,"|").")(\s\.\-\+\=)#is", "\1[censored]\3", $str);

Автор: PARROT 3.5.2006, 11:17
Жизнь заставила сделать фильтр слов:
В текстовом файле записаны слова:
mate.txt
Код

агрегат
агроном
адепт
азербайджанец
азиат
активист
албанец
алигарх
алигофрен

Делаю так:
Код

$badWords = explode("\r\n", file_get_contents("mate.txt"));
$mas_com[4] = str_replace($badWords, "**грязно ругается**", $mas_com[4]);

Результат:
Код

**грязно ругается**егат  (агрегат)
**грязно ругается**ивист (активист) 

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

Автор: Serkys 3.5.2006, 14:40
PARROT, а откуда у тебя берётся $mas_com? 

Автор: PARROT 3.5.2006, 14:46
Из базы. В базу пишется текст сообщения, в котором могут содержаться такие слова. 
Потом при выводе нужно все это заменить. 

Автор: Mal Hack 3.5.2006, 16:38
А если так:
Код
$badWords = file_get_contents("mate.txt");
$mas_com[4] = str_replace($badWords, "**грязно ругается**", $mas_com[4]);

 

Автор: IZ@TOP 3.5.2006, 16:46
Mal Hack, ммм... а в файле ж слова разделенные переносом строк... 

Автор: Mal Hack 3.5.2006, 16:54
Ах, ну да... Сорри, стормозил... Я бы тут альтернативной регуляркой прошолся бы. 

Автор: IZ@TOP 3.5.2006, 16:59
Mal Hack, да уж пробовали - regular expression too long  smile

Добавлено @ 16:59 
Предпологаю что на сервере все прекрасно заработает. У меня во всяком случае проблем не возникло. 

Автор: Mal Hack 3.5.2006, 17:06
Надо бы вывести через print_r массив полученных слов и посмотреть. Вероятно он битый.. 

Автор: PARROT 3.5.2006, 22:17
Странно, действительно на сервере все заработало: http://pk.traktora.spb.ru/index.php?page=comment&idp=98

(Меня Денвер начинает раздражать..., второй баг уже) 

Автор: Asbestos 30.6.2006, 07:20
Леди и мужики, ситуация следующая: замену в строках произвожу str_ireplace, НО это отказывается воспринимать верхний регистр кириллицы smile Знаю, что дуб и решение простое 

хехе прошу прощения, забыл указать верную локаль 

Автор: Gold Dragon 30.7.2006, 11:31
Народ, ещё раз про замену... Что-то код с регуляркой не работает.

$a = array ("aaa", "bbb", "ccc"); // что менять
$b = array ("111", "222", "333"); //yf что менять
$str = "aaa gaaa 1bbb bbb2 ccc qqq bbb! .aaa."; // где менять

в итоге не должны поменяться только "gaaa" и "qqq" 

Автор: Mal Hack 30.7.2006, 13:27
А что ты хочешь сделать?
Покажи код. 

Автор: Gold Dragon 30.7.2006, 17:13
Mal Hack, я твой пытался запустить

Код

$a = array ("ааа","1234","ёй");
$b = array ("ббб","4321","юй");
$str = "Строка в которой нужно искать и заменять";
$itog = preg_replace ("#(\s\.\-\+\=)(".implode($a,"|").")(\s\.\-\+\=)#is", "\1[censored]\3", $str);


Добавлено @ 17:14 

а так как я в регах ничего не понимаю, так и не разобрался... там явно не хватает $b 

Автор: Mal Hack 30.7.2006, 18:22
А тут ты так не сделаешь. Тут надо через preg_replace_callback 

Автор: Gold Dragon 30.7.2006, 18:39
Mal Hack, ну тебе виднее, а через preg_replace_callback  как ?
просто через str_replace работает не так. он заменяет внутри слова 

Автор: Mal Hack 30.7.2006, 21:34
Gold Dragon, поверь, я давно понял почему тебя str_replace не  устраивает smile)

Цитата(Gold Dragon @  30.7.2006,  19:39 Найти цитируемый пост)
ну тебе виднее, а через preg_replace_callback  как ?

Код

function repl( $matches )
{
/*
Тут надо поставиьь в соответствие что на что менять, это раз, а два проверить $matches[1] на не алфавитные символы. Проверь через ctype_*(), может придется и через регулярку.
*/
 return "что надо вернуть";
}
$a = array ("ааа","1234","ёй");
$b = array ("ббб","4321","юй");
$str = "Строка в которой нужно искать и заменять";
$itog = preg_replace_callback("#(\s\.\-\+\=)(".implode($a,"|").")(\s\.\-\+\=)#is", "repl", $str);
 

Автор: Gold Dragon 31.7.2006, 06:21
совсем запутался smile что-то не работает твой код

нужно это
Код

$a = array ("aaa", "bbb", "ccc");
менять на это
Код
$b = array ("111", "222", "333"); 


Mal Hack, зачем мне проверять слова на которые я меняю, ведь это мои слова замены, а не пользовательские?

зы
вот тестовая строка
Код

$str = "aaa gaaa 1bbb bbb2 ccc qqq bbb! .aaa."

 

Автор: GiV 31.7.2006, 10:49
Код

$a = array ("aaa", "bbb", "ccc"); 
$b = array ("111", "222", "333"); 
$str = "aaa gaaa 1aaa bbb2 ccc qqq 3ccc3 bbb! .aaa.";

$str = '~'.$str.'~';

for ($i=0; $i < count($a); $i++) {
    $str = preg_replace("/([^a-z])" . $a[ $i ] . "([^a-z])/ise", "replace('\\1', " . $b[ $i ] . " ,'\\2')", $str);
}

$str = trim($str, '#~');

echo $str;

function replace($pref, $body, $post) {
    return $pref. $body . $post;
}


Должно было работать и без функции replace ($str = preg_replace("/([^a-z])" . $a[ $i ] . "([^a-z])/is", "\\1" . $b[ $i ] . "\\2", $str);), соединяющей куски, но на двух серверах странное поведение было. 

Автор: Mal Hack 31.7.2006, 14:35
Плохое решение. ЛУчше 1 раз пройтись большой регуляркой, чем много маленькими.
Хотя и не всегда.
Да и замудренно как-то это.
Плюс, модификатор e сильно кушает память и может вызвать неприятности.
Плюс, помним, что ьез установки локали RegEX не будет работать с кирилицей в паттерне.
Код

<?php

    function repl( $matches )
    {
        global $b;
        global $a;
        print_r($matches);
        return $matches[1] . $b[ array_search( $matches[2] , $a ) ] . $matches[3];
    }
    
    $a = array ("aaa","1234","bbb");
    $b = array ("ббб","4321","юй");
    $str = "aaa gaaa 1bbb bbb2 ccc qqq bbb! .aaa.";
    
    $itog = preg_replace_callback("#([\s.-=;])(".implode($a,"|").")([\s.-=;])#i", "repl", $str);

    print $itog;
    
?>
 

Автор: GiV 31.7.2006, 16:05
Цитата(Mal Hack @  31.7.2006,  14:35 Найти цитируемый пост)
Плохое решение. ЛУчше 1 раз пройтись большой регуляркой, чем много маленькими.
Хотя и не всегда.

не всегда, хотя в данном случае правда Ваша. preg_replace с модификатором e работает медленне replace_callback 
+ мы всегда будем проходить все n итерации (n-количество элементов в массиве для замены), что в худшем случае (ни одного вхождения искомого ключа в строку) все n раз заставит сработать preg_replace в холостую. В то время как большой прег выполнится только ОДИН раз, там выигрыши получаются от 2-х мс...

И [\s.-=;] все же не все элементы включены (таб, запятая, восклицательный знак, двоеточие и т.д.), класс [^А-Яа-яA-Za-z] все же лучше. 

P.S. при достижении 100 с меня +. 

Автор: Gold Dragon 31.7.2006, 17:12
Наверное я слишком многое хочу  smile 


Mal Hack, не все условия выполняются: замена происходит только если в начале стоит цифра, пробелы или точки, остальные не меняются... 

Т.е. ещё нужны условия: граничит с восклицательным знаком, когда слово идёт сначала, когда заканчивается на цифру (или скорее всего не на букву)

 

Автор: Mal Hack 31.7.2006, 18:58
Цитата(GiV @  31.7.2006,  17:05 Найти цитируемый пост)
не всегда

Причем далеко не всегда. И сильно зависит от многих факторов.
В свое время пришлось на этом деле @ схомячить.

Цитата(GiV @  31.7.2006,  17:05 Найти цитируемый пост)
мы всегда будем проходить все n итерации (n-количество элементов в массиве для замены), что в худшем случае (ни одного вхождения искомого ключа в строку) все n раз заставит сработать preg_replace в холостую. 

Использование модификатора "e" очень частая ошибка многих пхпшников, которые наивно думают, что чем код короче, тем он быстрее smile
"e"незаменим, когда надо в заменяющую функцию передать НЕСКОЛЬКО параметров, часть из которых не из карманов. При работе с BB кодами e незаменим. Там уж никак.


Цитата(Gold Dragon @  31.7.2006,  18:12 Найти цитируемый пост)
щё нужны условия: граничит с восклицательным знаком, когда слово идёт сначала, когда заканчивается на цифру (или скорее всего не на букву)


Цитата(GiV @  31.7.2006,  17:05 Найти цитируемый пост)
И [\s.-=;] все же не все элементы включены (таб, запятая, восклицательный знак, двоеточие и т.д.),


Цитата(GiV @  31.7.2006,  17:05 Найти цитируемый пост)
класс [^А-Яа-яA-Za-z] все же лучше. 

Тут есть два момента. Первый - кирилица. Бывает глюит, надо локаль включать обязательно через set_locate().
Второй момент, все-таки помнтся мне, что был квантофикатор \b или \B, \W тут не подойдет.

И еще. [^А-Яа-яA-Za-z] все-таки большое-колво символов, а перечислив спецсимволы, как это сделал я, мы по логике получим в паттерне меньшее число проверок при компиляции, т.е. как мне кажется, указать все нужные спецсиволы будет лучше. 

Автор: GiV 31.7.2006, 19:30
Цитата(Mal Hack @  31.7.2006,  18:58 Найти цитируемый пост)
Второй момент, все-таки помнтся мне, что был квантофикатор \b или \B, \W тут не подойдет.

Границы слова. Они тоже зависят от локали, так как определение идет фактически на таких раздельных регулярках ^\w, \w$, \w\W, \W\w, а \w и \W включают различные наборы символов (коды символов не только до 128, но и больше)


Цитата(Mal Hack @  31.7.2006,  18:58 Найти цитируемый пост)
И еще. [^А-Яа-яA-Za-z] все-таки большое-колво символов, а перечислив спецсимволы, как это сделал я, мы по логике получим в паттерне меньшее число проверок при компиляции, т.е. как мне кажется, указать все нужные спецсиволы будет лучше.

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

Автор: Gold Dragon 24.4.2007, 12:33
так.. вопрос опять всплыл, но сейчас чуть всё проще, нужно тупо заменять слова. Просто не хочу сильно вымудряться. В общем есть массив со словами
Код

$filtr = array(
    'aaa',
    'bbb',
    'ccc',
    'ddd'
);

обработка простая
Код

function filtr($str){
    GLOBAL $filtr;
    $str = str_replace($filtr, '...', $str);
    return $str;
}

но как мне сделать чтоб слова сравнивались без учёта регистра, чтоб не писать
Код

$filtr = array(
    'aaa',
    'AaA',
    'AAA',
    'Aaa'
);

я пытался сделать
Код

$a1 = str_replace($filtr, '...', strtolower($str));
$a2 = strtolower($str);
$a3 = str_replace($filtr, '...', $str);
и сравнивать их, но запутался в логике :)


Что подскажите?


Автор: xolod 24.4.2007, 13:55
Код

// Регистро-независимый вариант функции str_replace()
str_ireplace

Автор: Gold Dragon 24.4.2007, 15:57
О как??? А я и не знал....
А синтаксис у неё такой же?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)