EN · DE · RU · FR · ES

#1873: DiffMatchPatch.java

projectforge-common/src/main/java/name/fraser/neil/plaintext/DiffMatchPatch.java Сторонняя библиотека (встроенная) — Google diff-match-patch, projectforge-common/src/main/java/name/fraser/neil/plaintext/DiffMatchPatch.java 2464 строки · 1638 кода · 688 комментариев · 138 пустых
Библиотека алгоритмов diff-match-patch от Google, автор Нил Фрейзер, встроена непосредственно в ProjectForge в оригинальном пакете name.fraser.neil.plaintext. Лицензия Apache License 2.0. Предоставляет синхронное сравнение текста (diff), нечёткое сопоставление (match) и применение патчей (patch) — те же алгоритмы, которые используются в Google Docs, Etherpad и сравнении версий Wikipedia. Используется ProjectForge для отслеживания изменений текста и сравнения версий.

Архитектура

Происхождение и лицензия

Обзор алгоритмов

Библиотека реализует три связанных алгоритма, все работают с обычным текстом:

1. Diff — алгоритм различий Майерса O(ND)

Вычисляет минимальный набор правок для преобразования text1 в text2. Основной алгоритм — алгоритм различий Майерса (1986), который находит кратчайший сценарий редактирования, используя подход O(ND) по времени/памяти, где N — сумма длин строк, а D — количество различий.

2. Match — алгоритм Bitap (Shift-Or)

Находит наилучшее приблизительное совпадение шаблона в большом тексте. Использует алгоритм Bitap (также известный как shift-or или алгоритм Баэзы-Йейтса–Гонне), который:

3. Patch — унифицированный формат diff + нечёткое применение

Создаёт патчи (текстовые представления различий), которые можно сериализовать, передавать и применять к другим текстам:

Ключевые параметры конфигурации

ПолеПо умолчаниюНазначение
Diff_Timeout1.0 секундаМаксимальное время для вычисления diff перед возвратом частичного результата (0 = бесконечно)
Diff_EditCost4Стоимость пустой операции редактирования — более высокие значения дают более чистые, менее фрагментированные различия
Match_Threshold0.5Порог нечёткого сопоставления (0.0 = точное, 1.0 = очень неточное)
Match_Distance1000Бонус за расположение — расстояние в символах от ожидаемой позиции совпадения
Patch_DeleteThreshold0.5Насколько точно блоки удаления должны соответствовать ожидаемому содержимому для принятия
Patch_Margin4Количество символов контекста вокруг фрагментов патча
Match_MaxBits32Разрядность для алгоритма Bitap (соответствует размеру int в Java)

Структура данных: Diff (внутренний класс)

Различия представлены как LinkedList<Diff>, где каждый Diff — это внутренний статический класс с:

Внутренний помощник: LinesToCharsResult

Оптимизация для больших текстов: преобразует строки в уникальные символы Unicode, выполняет diff над сжатым представлением, затем восстанавливает вывод на уровне строк. Это значительно сокращает пространство сравнения для текстов, ориентированных на строки (например, исходный код).

Импорты

Использование в ProjectForge

ProjectForge встраивает эту библиотеку, а не использует её как внешний JAR. Вероятно, это сделано потому, что:

  1. Библиотека стабильна и редко меняется (последнее значительное обновление — порт на Java около 2010 года)
  2. Встраивание позволяет избежать проблем управления зависимостями
  3. Имя пакета (name.fraser.neil.plaintext) уникально и не вызывает конфликтов
  4. Возможно, в неё внесены пользовательские изменения для нужд ProjectForge (хотя код выглядит как стандартный порт)
DiffMatchPatch используется для отслеживания изменений в текстовых полях объектов данных ProjectForge — показывает, что изменилось между версиями адреса, описания проекта или другого текстового содержимого.

Библиотека портирована на множество языков (Python, JavaScript, Java, C++, C#, Lua, Dart). Java-версия использует LinkedList для хранения diff, потому что различия в основном обходятся последовательно (не произвольный доступ), и алгоритм часто добавляет элементы в начало/конец.

История Git

48a93dedb Цветной лог консоли. Экспорт UserGroupCache для отладки и сравнения работы теперь доступен. CollectionUtil улучшен. Добавлен KotlinStringExtension.shortenMiddle().