Не существует встроенной функции PHP для достижения этой цели. Однако возможности PHP просто ограничены вашим воображением. Мы не можем на SO предлагать библиотеки для достижения вашей цели, и вам нужно помнить, что такого рода вопросы можно пометить как не по теме. Поэтому вместо того, чтобы предлагать некоторые библиотеки, я просто укажу вам, в каких направлениях вы должны исследовать.
Как и предполагалось, ваш вопрос предполагает, что вам не нужны простые функции сопоставления строк, такие как stripos
и co, и регулярное выражение не может этого достичь. Для примеров
уникальный и уникальный
, а также
идея и идея
не может соответствовать этим функциям. Поэтому вам нужно искать что-то вроде levenshtein
function
. Но так как вам нужны подстроки, а не вся строка, а также, чтобы упростить работу для levenshtein function
и вашего сервера, вы должны использовать немного воображения. Вы можете, например, break
оба haystack and needle
в словах, а затем использовать levenshtein
, чтобы найти наиболее близкие значения к вашим иглам.
Это один из способов достижения этого. Внимательно прочитайте комментарии, чтобы понять идею, и вы сможете реализовать что-то лучше.
для строк с только ASCII-символами это относительно легко достичь. Но для других кодировок вы, вероятно, столкнетесь со многими трудностями. Но простой подход к обработке многобайтовых строк тоже может быть что-то вроде:
function to_ascii($text,$encoding="UTF-8") {
if (is_string($text)) {
// Includes combinations of characters that present as a single glyph
$text = preg_replace_callback('/\X/u', __FUNCTION__, $text);
}
elseif (is_array($text) && count($text) == 1 && is_string($text[0])) {
// IGNORE characters that can't be TRANSLITerated to ASCII
$text = @iconv($encoding, "ASCII//IGNORE//TRANSLIT", $text[0]);
// The documentation says that iconv() returns false on failure but it returns ''
if ($text === '' || !is_string($text)) {
$text = '?';
}
elseif (preg_match('/\w/', $text)) { // If the text contains any letters...
$text = preg_replace('/\W+/', '', $text); // ...then remove all non-letters
}
}
else { // $text was not a string
$text = '';
}
return $text;
}
function find_similar($needle,$str,$keep_needle_order=false){
if(!is_string($needle)||!is_string($str))
{
return false;
}
$valid=array();
//get encodings and words from haystack and needle
setlocale(LC_CTYPE, 'en_GB.UTF8');
$encoding_s=mb_detect_encoding($str);
$encoding_n=mb_detect_encoding($needle);
mb_regex_encoding ($encoding_n);
$pneed=array_filter(mb_split('\W',$needle));
mb_regex_encoding ($encoding_s);
$pstr=array_filter(mb_split('\W',$str));
foreach($pneed as $k=>$word)//loop trough needle's words
{
foreach($pstr as $key=>$w)
{
if($encoding_n!==$encoding_s)
{//if $encodings are not the same make some transliteration
$tmp_word=($encoding_n!=='ASCII')?to_ascii($word,$encoding_n):$word;
$tmp_w=($encoding_s!=='ASCII')?to_ascii($w,$encoding_s):$w;
}else
{
$tmp_word=$word;
$tmp_w=$w;
}
$tmp[$tmp_w]=levenshtein($tmp_w,$tmp_word);//collect levenshtein distances
$keys[$tmp_w]=array($key,$w);
}
$nominees=array_flip(array_keys($tmp,min($tmp)));//get the nominees
$tmp=10000;
foreach($nominees as $nominee=>$idx)
{//test sound like to get more precision
$idx=levenshtein(metaphone($nominee),metaphone($tmp_word));
if($idx<$tmp){
$answer=$nominee;//get the winner
}
unset($nominees[$nominee]);
}
if(!$keep_needle_order){
$valid[$keys[$answer][0]]=$keys[$answer][1];//get the right form of the winner
}
else{
$valid[$k]=$keys[$answer][1];
}
$tmp=$nominees=array();//clean a little for the next iteration
}
if(!$keep_needle_order)
{
ksort($valid);
}
$valid=array_values($valid);//get only the values
/*return the array of the closest value to the
needle according to this algorithm of course*/
return $valid;
}
var_dump(find_similar('i knew you love me','finally i know you loved me and all my pets'));
var_dump(find_similar('I you love','This is a demo text and I love you about this'));
var_dump(find_similar('a unik idia','I have a unique idea. Do you need?'));
var_dump(find_similar("Goebel, Weiss, Goethe, Goethe und Goetz",'Weiß, Goldmann, Göbel, Weiss, Göthe, Goethe und Götz'));
var_dump(find_similar('Ḽơᶉëᶆ ȋṕšᶙṁ ḍỡḽǭᵳ ʂǐť ӓṁệẗ, ĉṓɲṩḙċťᶒțûɾ ấɖḯƥĭṩčįɳġ ḝłįʈ',
'Ḽơᶉëᶆ ȋṕšᶙṁ ḍỡḽǭᵳ ʂǐť ӓṁệẗ, ĉṓɲṩḙċťᶒțûɾ ấɖḯƥĭṩčįɳġ ḝłįʈ, șếᶑ ᶁⱺ ẽḭŭŝḿꝋď ṫĕᶆᶈṓɍ ỉñḉīḑȋᵭṵńť ṷŧ ḹẩḇőꝛế éȶ đꝍꞎôꝛȇ ᵯáꞡᶇā ąⱡîɋṹẵ.'));
и вывод:
array(5) {
[0]=>
string(1) "i"
[1]=>
string(4) "know"
[2]=>
string(3) "you"
[3]=>
string(5) "loved"
[4]=>
string(2) "me"
}
array(3) {
[0]=>
string(1) "I"
[1]=>
string(4) "love"
[2]=>
string(3) "you"
}
array(3) {
[0]=>
string(1) "a"
[1]=>
string(6) "unique"
[2]=>
string(4) "idea"
}
array(5) {
[0]=>
string(6) "Göbel"
[1]=>
string(5) "Weiss"
[2]=>
string(6) "Goethe"
[3]=>
string(3) "und"
[4]=>
string(5) "Götz"
}
array(8) {
[0]=>
string(13) "Ḽơᶉëᶆ"
[1]=>
string(13) "ȋṕšᶙṁ"
[2]=>
string(14) "ḍỡḽǭᵳ"
[3]=>
string(6) "ʂǐť"
[4]=>
string(11) "ӓṁệẗ"
[5]=>
string(26) "ĉṓɲṩḙċťᶒțûɾ"
[6]=>
string(23) "ấɖḯƥĭṩčįɳġ"
[7]=>
string(9) "ḝłįʈ"
}
если вам нужен вывод в виде строки, вы можете использовать join
для результата функции перед ее использованием
Вы можете запустить рабочий код и проверить результат онлайн
Но вы должны иметь в виду, что это не будет работать ни для всех типов строк, ни для всех версий PHP