Сравнение строк с выводом различий


Обработка созданная с целью представить реализованный мной алгоритм сравнения строк. Реализована на 1С 8.1, однако будет работать и на более поздних версиях.

Работая над обработкой сравнения документа с присланной версией печатной формы заказа в xls, столкнулся с необходимостью сообщать не только сам факт отличия в названиях товаров, но и информации о том, что конкретно отличается. Беглое знакомство с материалами Инфостарта не помогло — не нашел подходящего решения. Пришлось самому придумывать алгоритм. Получившийся инструмент показался мне полезным — потому решил поделиться ним.

Алгоритм: находим наибольшую общую подстроку двух строк (с помощью суффиксных автоматов http://e-maxx.ru/algo/suffix_automata) — получается что каждая строка разбита на 3 части: левая (еще не обработанная), средняя (это наибольшая общая подстрока) и правая (не обработанная). Левую и правую части обрабатываем таким же образом до тех пор, пока не сможем получить общую подстроку — в таком случае подстроки различны. В итоге получаем чередование совпадающих и не совпадающих подстрок.
Алгоритм выполнен без рекурсии — т.е. подходит для обработки больших строк.

Дополнительно для увеличения наглядности добавил вывод в html.

PS: если снова изобрел велосипед — прошу прощения за невнимательность.

16 Comments

  1. ildarovich

    Очень интересно!

    И построение суффиксного автомата на 1С запрограммировано. А это действительно сложный и нужный алгоритм. Его реализация и без обертки внешнего алгоритма имеет самостоятельное значение. — Замечательно!

    А быстродействие замеряли? — Как насчет действительно больших строк (например, миллион символов)?

    Можно ли применять для сравнения текстов модулей до и после изменений?

    В чем отличие от алгоритма Diff(наибольшая общая подпоследовательность)?

    Нет ли проблем неоднозначности (если одновременно нашлись в разных местах две наибольших совпадающих последовательности одинаковой длины)?

    Reply
  2. bahbah

    (1) ildarovich, быстродействие не замерял. Теоретически, отличия от алгоритма Diff в асимптотическом время работы алгоритма: Diff — O(n1*n2), суффиксные автоматы — O(n1+n2). Однако многое зависит от реализации.

    С трудом могу себе представить, где может быть использовано сравнение строк в цикле — это скорее разовая задача, хотя я могу ошибаться, поэтому существенной оптимизации и работы по поиску наиболее быстрого алгоритма не проводил. Остановился на алгоритме с хорошей зависимостью времени выполнения от объема данных. На протяжении полугода использования нареканий по скорости не было.

    Алгоритм хорошо себя показывает на родственных строках, в которых внесен небольшой шум.

    Проблема неоднозначности в общем случае присутствует, однако для конкретного применения — проблема редко встречается. Для текстов модулей проблема неоднозначности становится слишком серьезной — сравнение получается некрасивым. Возможно внесение дополнительных эвристик сделает этот алгоритм вполне конкурентоспособным и для сравнения модулей.

    Reply
  3. Virikus

    (2) Ну таких задач много, навскидку базы всяких рефератов, статей и т.д.

    Reply
  4. pallid

    Круто!!!

    Отдельно спасибо за ссылку на суффиксные автоматы

    Reply
  5. Ёпрст

    Зачетно!

    Пригодится на досуге.

    Reply
  6. Makushimo

    какой там велосипед?! -))

    очень здорово.

    Reply
  7. LexSeIch

    Мир этому дому!

    Отлично! Будет время, обязательно для себя разберусь с алгоритмом и теорией суффиксных автоматов. Автору большое спасибо!

    Reply
  8. ivanov660

    На мой взгляд правильнее выделять отдельные слова в отличии нежели отдельные части. К примеру, для 2,1 и 1,6 необходимо показать отличие целиком в числах нежели выделять отдельные цифры 2 и 6.

    Для таких вещей в принципе достаточно использовать метод шинглов. Работает он быстрее и проще, к тому же есть возможность настраивать уровень сравнения (шаг шингла). Единственная проблема, скорее проблема 1С, а не алгоритма — это отсутствие метода получения значения hash, md5.

    Reply
  9. bahbah

    (8) ivanov660, изначально этот алгоритм разрабатывался для сравнения названий номенклатуры. В целевой базе наименования довольно длинные и очень разнообразные — выделение различных слов приводит с сокращению размерности задачи — сравнению не всего названия, а нескольких слов, однако это все еще затруднительно делать глазами.

    Хорошей идеей будет совместить Ваше предложение — выделение отличных слов — с моим алгоритмом — в каждой паре различных слов выделить отличные символы.

    Однако и здесь возникает масса вопросов, например — если в исходной строке одно слово а на его месте в другой строке три слова, как быть?

    Reply
  10. kiruha

    А какие отличия от 1С встроенного СравнениеФайлов ?

    Кроме настроек которые есть в 1С

    1. Игнорировать пустое пространство

    2. Учитывать регистр

    3. Учитывать различия в разделителях строк

    Reply
  11. bahbah

    (10) kiruha, можно сказать, что в СравнениеФайлов единица сравнения — абзац, здесь — символ.

    Если бы СравнениеФайлов детализировала отличия до символа — не имело бы смысла делать эту обработку.

    Здесь все-таки основная задача сравнить 2 строки и показать конкретные различия, а не столько сам факт различия.

    Reply
  12. kiruha

    (11)

    Ок, спасибо, понятно — то же хорошо бы в публикации объяснить

    Reply
  13. bydk

    (8) ivanov660, в 8.3+ появилась возможность на уровне платформы получать разнообразные хеши…

     ХешMD5 = Новый ХешированиеДанных(ХешФункция.MD5);
    ХешMD5.Добавить(«Строка»);
    Результат = ХешMD5.ХешСумма;
    Reply
  14. yura1960

    Велосипед, но зачетный. Автору, в любом случае, спасибо. Как дополнительная опция к стандартным — подойдет.

    Reply
  15. user840225

    Замечена не очень корректная работа обработки (((

    При

    1 >Строка1 = «Оттмеченные»

    2 >Строка2 = «Отмеченые»

    Результат

    1 >Отмеченыеные

    2 >Отмеченые

    Если поменять строки местами, все вроде работает.

    Лучшая подстрока = «Отмечен» не существует в первой строке.

    Reply
  16. user840225

    Вышеуказанный алгоритм находит не наибольшую общую подстроку двух строк, а наибольшую последовательность символов.

    Я тут имел смелость (наглость?) дополнить авторскую обработку для решения этой задачи. Если найденная последовательность не является подстрокой, вызывается другой (не столь эффективный) алгоритм.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *