Как найти похожий текст в большой строке? - PullRequest
0 голосов
/ 27 октября 2018

У меня есть большая строка str и игла ndl. Теперь мне нужно найти похожий текст ndl из строки str. Например,

ИСТОЧНИК: «Это демонстрационный текст, и я люблю вас об этом».

ИГЛА: "Я тебя люблю"

ВЫХОД: «Я люблю тебя»


ИСТОЧНИК: «У меня есть уникальная идея. Вам нужна?».

ИГЛА: "unik idia"

ВЫХОД: «уникальная идея»

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

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

Это очень простой способ сделать это:

$source = "This is a demo text and I love you about this";
$needle = "I you love";
$words = explode(" " , $source);
$needleWords = explode(" ", $needle);
$results = [];

foreach($needleWords as $key => $needleWord) {

    foreach($words as $keyWords => $word) {

        if(strcasecmp($word, $needleWord) == 0) {
            $results[$keyWords] = $needleWord;
        }
    }
}
uksort($results, function($a , $b) {
    return $a - $b;
});
echo(implode(" " , $results));

выход

I love you
0 голосов
/ 28 октября 2018

Не существует встроенной функции 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

0 голосов
/ 27 октября 2018

Попробуйте этот код, чтобы найти строку в строке

$data = "I have a unique idea. Do you need one?";
$find = "a unique idea";
$start = strpos($data, $find);
if($start){     
    $end = $start + strlen($find);
    print_r(substr($data, $start, strlen($find)));
} else {
    echo "not found";
}
...