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

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

//Удаляем лишнее и разбиваем текст на слова и знаки препинания
$input = mb_strtolower($input);
$input = preg_replace('/[\\r\\n]/', ' ', $input);
$input = preg_replace('/[.,]/', ' $0', $input);
$words = preg_split('/ /', $input, 0, PREG_SPLIT_NO_EMPTY);

//Формируем словосочетания
foreach ($words as $key => $word) {
    //Прерываем цикл на последнем слове.
    if ($key == (count($words) - 1)) {
        break;
    }
    //Если текущее слово из списка стоп слов переходим к следуещему
    if (array_search($word, $stopWords) !== false) {
        continue;
    }
    $nextKey = $key + 1;
    //Если следующее слово из стоп слов переходим к следующему слову(по хорошему тут надо перескакивать через 1
    //но я хз как)
    if (array_search($words[$nextKey], $stopWords) !== false) {
        continue;
    }
    //Если же текущее и следующее слово в порядке составляем словосочетание из 2-х слов
    $twoWords[] = $word . ' ' . $words[$nextKey];
    //Так же проверяем предыдущее слово, если оно существует и не находится в стоп списке
    //делаем словосочетание из 3-х слов
    $prevKey = $key - 1;
    if ($prevKey < 0) {
        continue;
    } elseif (array_search($words[$prevKey], $stopWords) !== false) {
        continue;
    }
    $threeWords[] = $words[$prevKey] . ' ' . $word . ' ' . $words[$nextKey];
}

//Удаляем из массива со словами все что есть в стоп списке
foreach ($words as $key => $word) {
    if (array_search($word, $stopWords) !== false) {
        unset($words[$key]);
    }
}

//Считаем, удаляем все что было найдено 1 раз и сортируем
$countWords = array_diff(array_count_values($words), 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);

//Проверка наличия словосочетаний из 2-х слов и слов в словосочетаниях из 3-х
if (!empty($countThreeWords)) {
    foreach ($countThreeWords as $words3 => $count3) {
        foreach ($countTwoWords as $words2 => $count2) {
            if ((mb_strpos($words3, $words2) !== false) && ($count2 == $count3)) {
                unset($countTwoWords[$words2]);
            }
        }
        foreach ($countWords as $word => $count) {
            if ((mb_strpos($words2, $word) !== false) && ($count == $count3)) {
                unset($countWords[$word]);
            }
            $top[$words3] = $count3;
        }
    }
}
//Проверка наличия слов в словосочитаниях из 2-х слов
if (!empty($countTwoWords)) {
    foreach ($countTwoWords as $words2 => $count2) {
        foreach ($countWords as $word => $count) {
            if ((mb_strpos($words2, $word) !== false) && ($count2 == $count)) {
                unset($countWords[$word]);
            }
        }
        $top[$words2] = $count2;
    }
}
//Ну и если что то осталось загоняем в топ
if (!empty($countWords)) {
    foreach ($countWords as $word => $count) {
        $top[$word] = $count;
    }
}

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