Сравнение двух строк

Ashotovich

Новичок
Сравнение двух строк

Всем доброго дня.

Пытаюсь найти решение следующей задачи.
Есть: строка текста - название организации. Она хранится в БД. Существует возможность редактирование записи из формы.
Нужно: сравнить отредактированную строку с исходной на наличие кардинальных изменений и, в случае большого несовпадения строк, предложить сохранить запись как новую.

Как вариант можно рассмотреть такое: посимвольно запихиваем в один массив исходную строку, в другой - отредактированную строку, спавниваем в цикле массивы поэлементно. Количество совпадений делим на длину первого массива, получаем процент несовпадений. По нему и решаем - сохранить отредактированные данные в старую запись, или предложить создать новую.

Естественно, что данный метод не выдерживает никакой критики, ибо если пользователю вздумается вставить в начало строки только один символ, то вся строка "поедет" и несовпадений будет посчитано слишком много, хотя объективно в строке изменился только один символ.

Да, еще одна мысль - отсортировать оба массива при помощи sort() и сравнивать их не по позиции, а по по количеству букв алфавита, цифр и вспомогательных символов (допустим, в первом массиве 10 букв "а", 5 "б", 3 "в", а во втором - 8 букв "а", 6 "б" и 4 "в" - относительное несовпадение: 22%). Недостаток ясен - можно составить две абсолютно разных строки, состоящих из одих и тех же символов в одинаковых количествах - совпадение будет 100%.

Если есть какие мысли - поделитесь, плиииз.

Заранее спасибо.
 

Ashotovich

Новичок
О, levenshtein() - гениальная вещь! Работает как надо. Огромное спасибо - сам бы не допер.

Да, мне все же придется еще поизвращаться. Допустим, строка "Поликлиника №2" мало отличается от "Поликлиника №3". Но смысл-то разный выходит, ибо это-совершенно разные учреждения... Так что, похоже, придется мне еще искать в строках цифры и сравнивать. С другой стороны, нельзя исключить возможность простой опечатки в цифрах. Жуть. Мде... Буду думать.

В принципе, это можно сделать так: сканировать связанные таблицы в базе на предмет связи этой организации с другими записями в таблице и, в случае наличия оных связей - запрещать правку цифр. Если же запись не имеет связей - разрешить.
 

Ashotovich

Новичок
Да, а есть ли способ поиска числовых элементов строки попроще, нежели этот?:
PHP:
$strnumarr = array(); //Массив, куда буду заноситься числовые значения, "вытащенные" из строки

for ($i=0; $i<strlen($str); $i++)
   {
      $strelement = substr($str, $i, 1); //Текущий элемент строки
			if (is_numeric($strelement ))
         {
            if (isset($num)) $num = $num.$strelement ;
	        else $num = $strelement; //Переменная $num - число, извлекаемое из строки для записи в массив. Если она еще не задана, значит цифра - первая из стоящих подряд, если задана - значит "приклеиваем" ее к предыдущей (тут преобразуется тип из числового в строковой)
         }
      elseif (isset($num))
         {
            array_push($strnumarr, $num);
            unset($num);
         }
   }
if (isset($num)) array_push($strnumarr, $num); //Если цифры - последние в строке, цикл их не захватывает. Исправляю этот недочет
Таким образом я получу массив всех чисел из строки (если я чего не накосячил ;)). То есть, если строка имеет вид "абвгдеж123 иклмн №12 уфхцчшщ 144", то массив будет следующим: Array ( [0] => 123 [1] => 12 [2] => 144 ). Провожу ту же операцию для второй строки, получаю массив, сравниваю оба массива, если нахожу несоответсвия - предлагаю завести новую запись в базе.

Конструкция весьма громоздка - что скажете? Есть ли способы вытяжки из строки всех чисел попроще?
 

Falc

Новичок
Ashotovich
Какое отношение приведенй код имеет к поставленой задаче в начеле темы.
P.S. Выжимка чисел из строки делается одним регом.
 

Ashotovich

Новичок
Falc,
Это имеет отношение к сравнению строк. Я же написал - levenshtein() - отличная функция, но она не решает всех проблем, то есть проблем смыслового различия строк. Если в строке изменить всего один символ - цифру, то весь смысл может измениться кардинально,. пример я приводил. Поэтому кроме levenshtein() придется сравнивать строки отдельно по совпадению цифр.

Да, про регулярное выражение я чего-то не сообразил сразу - мысль в другую сторону пошла. Точно - и кода будет меньше, и считать будет быстрее. Спасибо за вразумление. Ступил я чего-то неслабо... ;)

Не могли бы Вы дать наводящую мысль по поводу регулярного выражения, вытаскивающего из строки все цифры с разделителями отдельно стоящих чисел? В регах я не особо силен...
 

Falc

Новичок
Если ты почитаешь топик на который я дал ссылку, то можешь узнать много интересного, например, то что лучше сравнивать не сами исходные строки, а 1-байтовые хеши слов, в твоем случае число ты можешь считать как отдельное слово, по этому изменения числа будет равнослиьно изменению слова.
Хотя если у тебя названия совсем короткие 1-2 слова, то может это тебе не подойдет.
 

Ashotovich

Новичок
О! Спасибо огромное. Правда, нулевой элемент массива всегда пустой получается... Но, думаю, это не проблема. Спасибо еще раз! :)
 

Ashotovich

Новичок
В большинстве случаев названия короткие. "Поликлиника № 1", "Больница № 5" и пр.
 

Falc

Новичок
У функции preg_split, есть еще 3-ий параметр посмотри ман.
 

Ashotovich

Новичок
Точно. PREG_SPLIT_NO_EMPTY решит проблему (он, правда, четвертый; третий - limit). Many thanks
 
Сверху