<?php
// Топ N самых часто встречающихся слов и словосочетаний в тексте(из 2-3-х слов)
mb_internal_encoding('Utf-8');

$stopWords = array('и', 'у', 'к', 'с', 'о', 'от', 'в', 'же', 'из', 'на', 'не', 'вы', 'как',
    'но', 'чтобы', 'что');
$input = 'Эта функция сортирует массив в обратном порядке таким образом, что
сохраняются отношения между ключами и значениями. Сохраняются отношения и
сохраняются отношения и еще сохраняются отношения и опять сохраняются отношения.';

// Функция удаляющая слова и словосочетания являющиеся частью больших словосочений
function removeRepetition($moreWords, $words)
{
    // Создаем индекс слов из больших словосочетаний
    $bigPhrases = array_keys($moreWords);
    foreach ($bigPhrases as $moreKey => $moreWord) {
        $temp = explode(' ', $moreWord);
        foreach ($temp as $value) {
            $index[$value][] = $moreKey;
        }
    }
    if (!isset($index)) {
        return $words;
    }
    // Если во втором массиве словосочетания, иначе слова
    foreach ($words as $key => $value) {
        if (preg_match('/\w+ \w+/u', $key)) {
            $tempWords = explode(' ', $key);
            $word1Keys = $index[$tempWords[0]];
            $word2Keys = $index[$tempWords[1]];
            $result = array_intersect($word1Keys, $word2Keys);
            if ( !empty($result) ) {
                unset($words[$key]);
            }
        } else {
            if (isset($index[$key])) {
                unset($words[$key]);
            }
        }
    }
    return $words;
}

// Разбиваем текст на предложения
$input = mb_strtolower($input);
$input = preg_replace('/\s+/u', ' ', $input);
$input = preg_replace('/[^\w.!?\s]/u', '', $input);
$input = trim($input);
$sentences = preg_split('/[.!?]/', $input, 0, PREG_SPLIT_NO_EMPTY);

// Формируем словосочетания
foreach ($sentences as $sentence) {
    $sentence = trim($sentence);
    $words = preg_split('/ /', $sentence, 0, PREG_SPLIT_NO_EMPTY);
    $words = array_values(array_diff($words, $stopWords));
    for ($i = 0; $i < (count($words) - 1); ++$i) {
        $oneWords[] = $words[$i];
        $twoWords[] = $words[$i] . ' ' . $words[$i + 1];
        if ($i !== 0) {
            $threeWords[] = $words[$i - 1] . ' ' . $words[$i] . ' ' . $words[$i + 1];
        }
    }
    $oneWords[] = $words[$i];
}

// Считаем, удаляем все что было найдено 1 раз и сортируем
$countWords = array_diff(array_count_values($oneWords), array(1));
$countTwoWords = array_diff(array_count_values($twoWords), array(1));
$countThreeWords = array_diff(array_count_values($threeWords), array(1));
arsort($countWords, SORT_NUMERIC);
arsort($countTwoWords, SORT_NUMERIC);
arsort($countThreeWords, SORT_NUMERIC);

// Удаляем слова и словосочеания являющиеся часть других
$countWords = removeRepetition($countThreeWords, $countWords);
$countWords = removeRepetition($countTwoWords, $countWords);
$countTwoWords = removeRepetition($countThreeWords, $countTwoWords);

$top = array_merge($countWords, $countTwoWords, $countThreeWords);

// Выводим результат нашей магии
if (!count($top)) {
    echo 'Увы, но в данном тексте нет частых слов или словосочетаний встречающихся больше одного раза :(';
} elseif (count($top) == 1) {
    foreach ($top as $words => $count) {
        echo 'Самое частое слово/словосочетание: "' . $words . '", оно встречается - ' . $count .
            ' раз.';
    }
} else {
    arsort($top);
    echo "Самые частые слова/словосочетания:\n";
    foreach ($top as $words => $count) {
        echo $words . " - встречается " . $count . " раз.\n";
    }
}