За последние 24 часа нас посетили 18320 программистов и 1650 роботов. Сейчас ищут 1069 программистов ...

Детальное сравнение строк

Тема в разделе "Решения, алгоритмы", создана пользователем Dagdamor, 3 авг 2007.

  1. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Дано: две строки, $str1 и $str2 (предположим, старая и новая версии статьи).
    Задача: сравнить и определить, что в новой версии добавилось, что исчезло, что осталось без изменений.

    Пример:
    $str1="У Мэри был ягненок.";
    $str2="У Мэри был ягненок, и она его любила.";

    Результат: структура примерно такого вида:

    Код (Text):
    1. array(
    2.   array(
    3.     "type"=>"unchanged"
    4.     "text"=>"У Мэри был ягненок"
    5.   )
    6.   array(
    7.     "type"=>"added"
    8.     "text"=>", и она его любила"
    9.   )
    10.   array(
    11.     "type"=>"unchanged"
    12.     "text"=>"."
    13.   )
    14. )
    Соответственно есть 3 типа блоков: unchanged, added и removed.
    Есть хорошие идеи, как такое реализовать?
     
  2. stas_t

    stas_t Активный пользователь

    С нами с:
    24 апр 2007
    Сообщения:
    500
    Симпатии:
    0
    Адрес:
    Courbevoie, France
  3. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    stas_t
    Ух... сколько букав :(
    Я надеялся, что будет что-нибудь попроще...
     
  4. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    боюсь эта задача NP-полная :)
     
  5. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Первое, что приходит в голову:
    1. Разбиваем строки на слова (получаем массив слов)
    2. Последовательно сравниваем значения массивов.
    2.1. Если значения ключей равны, то едемдальше.
    2.2. Если не равны, то ищем в «новом» массиве следующее значение «старого» массива. Разница по сути и есть «добавление». Ну и едем дальше.

    Недостаток: надо продумать такой момент: удаление из исходной строки какого-либо слова.
     
  6. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    как вариант: из одной строки делаем регулярку типа
    Код (Text):
    1. /^(.*?)(a?)(.*?)(b?)(.*?)(c?)(.*?)$/
    - это для строки "abc"
    c помощью этой регулярки во второй строке находим "костяк" - группы символов (и их координаты), которые не изменились. затем находим изменившиеся подстроки между элементами "костяка".
     
  7. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Пара пожеланий/уточнений к алгоритму:
    - он не должен разбивать слова (как упомянул AlexGousev);
    - если два фрагмента поменялись местами, то желательно, чтобы больший из них пометился как не изменившийся, а меньший - как удаленный в одном месте и добавленный в другом.

    Пока что, как мне кажется, задача сводится лишь к поиску одинаковых фрагментов, все остальное несложно...
     
  8. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Значит, для начала, надо определиться, на какие фрагменты разбивать строку, чтобы производить сравнение. diff разбивает по строчкам. Можно разбивать по предложениям, словам, парам-тройкам слов и т.п.

    Соответственно и поиск изменений будет производится именно с той точностью, какую выберем при разбивке.
     
  9. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    AlexGousev, он хочет разбиения по 8 бит ;)
     
  10. Davil

    Davil Guest

    Dagdamor
    зачем велосипед изобретать, возьми исходники svn(C), или eventum(php), да посмотри как это реализовано там.
     
  11. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Davil
    Там стандартный diff, который бьет по строкам.
     
  12. Davil

    Davil Guest

    и это такая серьезная проблема?
     
  13. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Davil
    Ну как тебе сказать, я изложил задачу в первой мессаге, а ты предложил решение для другой задачи ;)
    А так никаких проблем.
     
  14. Davil

    Davil Guest

    что не так?
     
  15. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    AlexGousev
    Разбиваем с точностью до символа, но слова не трогаем. То есть разбивка по словам, а за пределами слов - посимвольная. Слово - [a-zA-Zа-яА-Я_]+. Вроде такой вариант звучит наиболее логично.

    Davil
    Насколько я понял, diff, который ты предлагаешь, сравнивает фрагменты с точностью до строки, а здесь понятия строки вообще нет - текст идет сплошным потоком. Переносы строк могут быть, но они не являются разделителями, просто часть текста.
     
  16. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    Dagdamor, что за задачу-то ты решаешь?
     
  17. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    AlexGousev
    Кстати - что значит фраза "стандартный diff"? В каком смысле стандартный?

    dark-demon
    Пишу библиотеку, которая потребуется плагину для моего движка. Смысл в том, чтобы не выводить два экземпляра статьи слева и справа, как в Википедии, а отобразить статью целиком, фоновым цветом подкрасив изменившиеся (удаленные и добавленные) области.
     
  18. Davil

    Davil Guest

    Dagdamor
    я не предлагаю diff.
    Я предлагаю реализацию.
    А diff заменить на что-то другое - это такая серьезная проблема?
     
  19. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    Dagdamor, тогда проще производить редактирование через специальный редактор на базе design-mode, который бы при нажатии на del обрамлял бы выделенное тэгом <del>, а набираемый текст - тегом <ins>
     
  20. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    dark-demon
    Это мне не слишком поможет, если версий более двух и требуется их сравнивать попарно.
     
  21. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    а зачем тебе хранить десять версий? вики делаешь? :)