Различия должны содержать достаточно информации, чтобы можно было вставить одну версию в другую, так что да, для вашего эксперимента по изменению одной строки на очень маленький документ, хранение целых документов может быть дешевле.
Библиотечные функции возвращают итераторы, чтобы облегчить работу с клиентами, которые испытывают нехватку памяти или должны просматривать только часть полученной последовательности.Это нормально в Python, потому что каждый итератор может быть преобразован в список с очень коротким list(an_iterator)
выражением.
Большая часть различий выполняется по строкам текста, но можно перейти к символу-по-порядку.char, и difflib
делает это.Взгляните на Differ
класс объектов в difflib
.
В примерах повсюду используются удобные для человека результаты, но различия управляются изнутри гораздо более компактным и удобным для компьютера способом.Кроме того, различия обычно содержат избыточную информацию (например, текст удаляемой строки), чтобы сделать исправления и объединить изменения безопасными.Избыточность может быть удалена вашим собственным кодом, если вам это удобно.
Я только что прочитал, что difflib
выбирает наименьшее удивление в пользу оптимальности, с чем я не буду спорить.Существуют хорошо известные алгоритмы, которые быстро производят минимальный набор изменений.
Однажды я кодировал универсальный механизм вычисления и один из оптимальных алгоритмов в 1250 строках Java ( JRCS ).Это работает для любой последовательности элементов, которые можно сравнить на равенство.Если вы хотите создать собственное решение, я думаю, что перевод / переопределение JRCS должно занять не более 300 строк Python.
Также возможна обработка выходных данных, создаваемых difflib
, чтобы сделать его более компактным.Это пример небольших файлов с тремя изменениями (добавление, изменение и удаление):
---
+++
@@ -7,0 +7,1 @@
+aaaaa
@@ -9,1 +10,1 @@
-c= 0
+c= 1
@@ -15,1 +16,0 @@
- m = re.match(code_re, text)
То, что говорится в патче, может быть легко сжато:
+7,1
aaaaa
-9,1
+10,1
c= 1
-15,1
Для вашего собственного примера сжатый вывод будет выглядеть следующим образом:
-8,1
+9,1
print "The end"
В целях безопасности оставление в начале маркера ('>') для строк, которые должны быть вставлены, может быть хорошей идеей.
-8,1
+9,1
>print "The end"
Это ближе к тому, что вам нужно?
Это простая функция для уплотнения.Вам придется написать собственный код, чтобы применить патч в этом формате, но он должен быть простым.
def compact_a_unidiff(s):
s = [l for l in s if l[0] in ('+','@')]
result = []
for l in s:
if l.startswith('++'):
continue
elif l.startswith('+'):
result.append('>'+ l[1:])
else:
del_cmd, add_cmd = l[3:-3].split()
del_pair, add_pair = (c.split(',') for c in (del_cmd,add_cmd))
if del_pair[1] != '0':
result.append(del_cmd)
if add_pair[1] != '0':
result.append(add_cmd)
return result