Когда Госдума публикует текст законопроекта ко второму чтению, поправки традиционно показывают не построчным diff, а зачёркиванием и полужирным прямо в тексте документа — "исключить слова", "дополнить абзацем". Программный diff решает ту же задачу иначе: сравнивает две версии текста и находит минимальный набор строк, которые нужно убрать и добавить, чтобы получить вторую версию из первой.
Наибольшая общая подпоследовательность
В основе алгоритма — поиск наибольшей общей подпоследовательности (LCS) строк между двумя версиями. Строки, вошедшие в неё, считаются неизменными; всё остальное помечается как удалённое из старой версии либо добавленное в новую. Результат — минимальный набор правок, а не первый попавшийся способ превратить один текст в другой.
Как читать результат
Удалённые строки обычно помечаются знаком - и красным цветом, добавленные — + и зелёным. Строка, которая по смыслу «изменилась», технически показывается как удаление старой и добавление новой — diff не различает редактирование строки как отдельную операцию, только удаление и добавление.
Почему построчное сравнение иногда обманывает
Если в середину текста вставить одну новую строку, построчное сравнение может показать «изменёнными» все последующие строки — алгоритм не всегда угадывает, что это вставка, а не массовая замена. Это особенно заметно при сравнении переводов интерфейса на .po или .json: добавление одной строки в середину файла сдвигает нумерацию и создаёт лавину ложных отличий.
Зачем это нужно
- Проверить, что именно изменилось между двумя версиями конфига, документа или локализации.
- Разобраться в code review, понимая логику алгоритма поиска отличий.
- Сравнить вывод скрипта до и после рефакторинга, чтобы убедиться в отсутствии регрессий.
Diff на уровне строк против уровня символов
Построчное сравнение годится для кода и конфигов, но для прозы или длинного предложения, где изменилось одно слово, оно пометит всю строку как удалённую и добавленную заново. Diff на уровне слов или символов внутри строки точнее показывает именно изменившийся фрагмент — ценой более высокой вычислительной сложности на больших текстах.