Blog. Just Blog

Проверка похожести двух слов

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Точное сравнение двух символьных строк, даже регистронезависимое, выполнить нетрудно. А как быть, если в одной их них встречаются символы другого алфавита, похожие по написанию? Так, буква "E" в русской и английской раскладке имеет одинаковое написание, или вместо русской "Н(н)" можно написать английскую "H(h)". Этим могут воспользоваться всякие ублюдки, например оставить сообщение на форуме якобы от администрации, зарегистрировав ник, внешне похожий на ник одного из админов. Для проверки похожести двух строк я использую следующую функцию:
  1. // -----------------------------------------------------
  2. // Функция проверки похожести двух слов
  3. // Параметры: $name1 и $name2 - слова для проверки
  4. // $register = TRUE - проверка регистронезависима
  5. //           = FALSE - проверка с учетом регистра
  6. // На выходе: TRUE - слова похожи, FALSE - отличаются
  7. // -----------------------------------------------------
  8. function chk_similarity($word1$word2$register=false) {
  9.   // Очистить слова от служебных символов
  10.   $word1=eregi_replace("[^0-9a-zа-я]","",$word1);
  11.   $word2=eregi_replace("[^0-9a-zа-я]","",$word2);
  12.  
  13.   // Возврат FALSE если длина слов различается
  14.   // или хотя бы одно из них пустое
  15.   if ((strlen($word1)!==strlen($word2)) || strlen($word1)*strlen($word2)==0) {
  16.     return false;
  17.   }
  18.  
  19.   // Заполнить таблицу соответствий
  20.   $pattern1="";
  21.   $pattern2=Array();
  22.  
  23.   $pattern1.="aа";
  24.   $pattern2[]="[аa]";
  25.   $pattern2[]="[аa]";
  26.  
  27.   $pattern1.="AА";
  28.   $pattern2[]="[АA]";
  29.   $pattern2[]="[АA]";
  30.  
  31.   $pattern1.="BВ";
  32.   $pattern2[]="[BВ]";
  33.   $pattern2[]="[BВ]";
  34.  
  35.   $pattern1.="bь";
  36.   $pattern2[]="[bь]";
  37.   $pattern2[]="[bь]";
  38.  
  39.   $pattern1.="cс";
  40.   $pattern2[]="[cс]";
  41.   $pattern2[]="[cс]";
  42.  
  43.   $pattern1.="CС";
  44.   $pattern2[]="[CС]";
  45.   $pattern2[]="[CС]";
  46.  
  47.   $pattern1.="eе";
  48.   $pattern2[]="[eе]";
  49.   $pattern2[]="[eе]";
  50.  
  51.   $pattern1.="EЕ";
  52.   $pattern2[]="[EЕ]";
  53.   $pattern2[]="[EЕ]";
  54.  
  55.   $pattern1.="HН";
  56.   $pattern2[]="[HН]";
  57.   $pattern2[]="[HН]";
  58.  
  59.   $pattern1.="iI1l";
  60.   $pattern2[]="[iI1l]";
  61.   $pattern2[]="[iI1l]";
  62.   $pattern2[]="[iI1l]";
  63.   $pattern2[]="[iI1l]";
  64.  
  65.   $pattern1.="kк";
  66.   $pattern2[]="[kк]";
  67.   $pattern2[]="[kк]";
  68.  
  69.   $pattern1.="KК";
  70.   $pattern2[]="[KК]";
  71.   $pattern2[]="[KК]";
  72.  
  73.   $pattern1.="MМ";
  74.   $pattern2[]="[MМ]";
  75.   $pattern2[]="[MМ]";
  76.  
  77.   $pattern1.="nп";
  78.   $pattern2[]="[nп]";
  79.   $pattern2[]="[nп]";
  80.  
  81.   $pattern1.="oо0";
  82.   $pattern2[]="[oо0]";
  83.   $pattern2[]="[oо0]";
  84.   $pattern2[]="[oо0]";
  85.  
  86.   $pattern1.="OО0";
  87.   $pattern2[]="[OО0]";
  88.   $pattern2[]="[OО0]";
  89.   $pattern2[]="[OО0]";
  90.  
  91.   $pattern1.="pр";
  92.   $pattern2[]="[pр]";
  93.   $pattern2[]="[pр]";
  94.  
  95.   $pattern1.="PР";
  96.   $pattern2[]="[PР]";
  97.   $pattern2[]="[PР]";
  98.  
  99.   $pattern1.="rг";
  100.   $pattern2[]="[rг]";
  101.   $pattern2[]="[rг]";
  102.  
  103.   $pattern1.="TТ";
  104.   $pattern2[]="[TТ]";
  105.   $pattern2[]="[TТ]";
  106.  
  107.   $pattern1.="uи";
  108.   $pattern2[]="[uи]";
  109.   $pattern2[]="[uи]";
  110.  
  111.   $pattern1.="xх";
  112.   $pattern2[]="[xх]";
  113.   $pattern2[]="[xх]";
  114.  
  115.   $pattern1.="XХ";
  116.   $pattern2[]="[XХ]";
  117.   $pattern2[]="[XХ]";
  118.  
  119.   $pattern1.="yу";
  120.   $pattern2[]="[yу]";
  121.   $pattern2[]="[yу]";
  122.  
  123.   $pattern1.="YУ";
  124.   $pattern2[]="[YУ]";
  125.   $pattern2[]="[YУ]";
  126.  
  127.   $pattern1.="З3";
  128.   $pattern2[]="[З3]";
  129.   $pattern2[]="[З3]";
  130.  
  131.   $pattern1.="ч4";
  132.   $pattern2[]="[ч4]";
  133.   $pattern2[]="[ч4]";
  134.  
  135.   $pattern1.="Ч4";
  136.   $pattern2[]="[Ч4]";
  137.   $pattern2[]="[Ч4]";
  138.  
  139.   // Составить регулярное выражение для проверки
  140.   $tmp="^";
  141.   for ($i=0$i<strlen($word1); $i++) {
  142.     $letter=$word1[$i];
  143.     $pos=strpos($pattern1,$letter);
  144.     if ($pos===false) {
  145.       $tmp.=$letter;
  146.     }
  147.     else {
  148.       $tmp.=$pattern2[$pos];
  149.     }
  150.   }
  151.   $tmp.="$";
  152.  
  153.   // Возврат TRUE - слова похожи или равны
  154.   // FALSE - слова отличаются
  155.   return($register?eregi($tmp,$word2):ereg($tmp,$word2));
  156. }
Примеры использования:
  1. $admin_name="ManHunter";   // Ник администратора
  2.  
  3. $chk_name="МаnНuntеr";     // Буквы "М", "Н" и "е" в русской раскладке
  4. chk_similarity($admin_name$chk_name);     // --> TRUE
  5.  
  6. $chk_name="manhunter";     // Буквы в нижнем регистре
  7. chk_similarity($admin_name$chk_name);     // --> FALSE
  8. chk_similarity($admin_name$chk_name1);  // --> TRUE
  9.  
  10. $chk_name="[Man_Hunter]";  // Использованы служебные символы
  11. chk_similarity($admin_name$chk_name);     // --> TRUE
  12.  
  13. $chk_name="-=mAnHuNtEr=-"// Регистр и служебные символы
  14. chk_similarity($admin_name$chk_name);     // --> FALSE
  15. chk_similarity($admin_name$chk_name1);  // --> TRUE
  16.  
  17. $chk_name="ManHanter";     // Слово не похоже
  18. chk_similarity($admin_name$chk_name);     // --> FALSE
  19. chk_similarity($admin_name$chk_name1);  // --> FALSE
Теперь враг не пройдет :) Функцию без особого труда можно модифицировать, чтобы она возвращала регулярное выражение для поиска соответствий по базе.

Поделиться ссылкой ВКонтакте
Просмотров: 4737 | Комментариев: 14

Метки: PHP
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
ManHunter (28.04.2015 в 11:35):
В сторону mb_ereg, mb_ereg_match, preg_replace + '/u', preg_match + '/u'
Роман (27.04.2015 в 13:20):
В общем-то вопрос в другом: в какую сторону мыслить для переделки под utf-8?
Роман (27.04.2015 в 12:31):
ManHunter, Ну да, я заюзал с исходника - не запахало, отписался.
Только потом сел и стал перечитывать каждую строчку:)
Всё норм:)
ManHunter (27.04.2015 в 12:21):
Ну дык, статья 2008 года, на календарик сам посмотришь? Все примеры для win1251, eregi/ereg давно уже превратились в preg_match, и так далее.
Роман (27.04.2015 в 12:01):
В принципе, не работает.
Т.е. не то что бы попытка использовать в своих целях - проваливается, а сами пос ебе прмиеры даже не срабатывают.
??nH?nt?r (15.04.2011 в 00:07):
Я тоже чем-то наподобие страдал лет 5 назад, но логин админа я сразу сделал красным цветом, чтоб никто не путался :)
ipSlicer (01.02.2009 в 05:01):
Sorry. Не заметил - coockie сохранил ManHanler =) Исправляю оплошность.
ManHunter (31.01.2009 в 10:20):
ipSlicer, это более правильное решение. Сделал выделение цветом. А ник все-таки поменяй, не искушай судьбу :)
ManHanIer (31.01.2009 в 06:38):
ManHunter, бан - это понятно =) Но вообще-то для таких целей, применительно к авторским ресурсам, более эффективно, имхо, использовать ассоциативно-зрительные методы. Проще говоря, прописывай себя в комментах, к примеру, синим цветом или полужирным шрифтом и посетители, не поведутся на подделку просто в силу того, что автор будет у них ассоциироваться больше не по написанию ника, а по цвету или шрифту.
ManHunter (29.01.2009 в 08:53):
ipSlicer, горячки боя тут нет, все тихо и спокойно, так что все такие попытки будут однозначно заканчиваться баном :) Это не конкретно к тебе относится, а вообще, если будут умышленные прецеденты.
ManHanIer (29.01.2009 в 04:17):
Моя несогласен. =) Сам подумай - введение ограничений на одноязычный ввод ника исключает возможность его подделки указанным тобой способом. В три строчки. Придумано не мной. Большинство online-игр имеют подобное условие при авторизации и отсекают подобные поползновения еще на стороне пользователя. Кста, в примере с твоим ником, я могу написать и так. В горячке боя могут незаметить, что буковка "t" заменена на "l".
----------------------
С уважением, ipSlicer.
ManHunter (27.01.2009 в 03:04):
ipSlicer, ты не путай мягкое и теплое. Тут смысл в том, чтобы никто не мог использовать _похожие_ ники, смотри прилагаемый пример. Или вот практическое применение: на этом блоге под ником "ManHunter" камменты могу писать только я, и то только когда залогинен в админке. В чате то же самое.
ipSlicer (27.01.2009 в 03:01):
В случае авторизации, имхо, достаточно просто проверить ввод пользователя на смешенность регистра ввода и послать его лесом, если таковой имеет место быть:

$str1=$user_input;
$str2=preg_replace('/[^a-zA-Z]/i','',$user_input);
return($str1==$str2?true:false);

ЗЫ. рад снова видеть Region59.net
CoStick (11.01.2009 в 12:52):
Аналогичную функцию пришлось писать года 3 назад, но для UTF-8, хотел запостить творение, но ограничение в 2000 не позволило этого сделать.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0071 сек.) / Память: 4.5 Mb
Наверх