Еще одно решение - вычислить расстояние Левенштейна между строками
https://www.php.net/manual/ru/function.levenshtein.php
Расстояние Левенштейна - это минимальное количество вставок, замен и удалений символов, необходимое для преобразования str1 в str2. Сложность алгоритма равна O(m*n), где n и m - длины строк str1 и str2 (неплохо по сравнению с similar_text(), имеющей сложность O(max(n,m)**3), но все же довольно много).
echo(levenshtein('abcdefg', 'amcdehg'));
Если расстояние между строками равно 2, значит нужно вставить, заменить или удалить 2 символа, соответственно строки похожи.
Функция для работы с русским языком:
https://gist.github.com/shankao/b0d92e15c65852fda481
Пример:
$lines = [
'Продам клинок демона +6 / Солнцеликий плащ +2 тьма',
'Продам клинок демона +6, Солнцеликий плащщ +2тьма',
'Акция! Продам клинок демона +6, Солнцеликий плащ +2тьма',
'Продам клинок ангела +3, Луноликая куртка +4свет',
'Продам клинок ангелла +3, Луноликая куртка +4свет',
'Акция ! Продам клинок ангела +3, Луноликая куртка +4свет',
'тест акции',
'проверка демона',
'проверка ангела',
];
$res = [];
$allSimilar = [];
foreach ($lines as $line) {
$similarLines = [];
if(in_array($line, $allSimilar)) {
continue;
}
foreach ($lines as $line1) {
$lev = mb_levenshtein($line, $line1);
$maxDistance = (int)(0.2 * max(mb_strlen($line), mb_strlen($line1)));
if($lev <= $maxDistance) {
$similarLines[] = $line1;
$allSimilar[] = $line1;
}
}
$res[$line] = $similarLines;
}
print_r($res);
Похожими считаются фразы, которые отличаются менее чем на 20% их длины.