Как использовать difflib Python для сравнения двух файлов, аналогичных команде Unix sdiff?
Я использую Python 2.6 и хочу создать простой графический интерфейс с двумя параллельными текстовыми панелями, сравнивающими два текстовых файла (file1.txt & file2.txt).
Я использую difflib, но мне не ясно, как получить результат, похожий на команду Unix sdiff.
Чтобы воспроизвести параллельное сравнение, мне нужен difflib, чтобы вернуть две переменные file1_diff
а также file2_diff
, например.
Я также решил использовать вывод sdiff напрямую и проанализировать его для разделения панелей, но оказалось, что это не так просто, как кажется... Есть подсказки?
4 ответа
Основываясь на ответе @Bryan Oakley, я написал краткую суть:
https://gist.github.com/jlumbroso/3ef433b4402b4f157728920a66cc15ed
с помощью метода параллельного сравнения (включая метод создания этого параллельного расположения с использованием
textwrap
библиотеку), которую вы можете вызывать в двух списках строк:
print(better_diff(
["a", "c", "a", "a", "a", "a", "a", "a", "e"],
["a", "c", "b", "a", "a", "a", "a", "d", "a", "a"],
width=20,
as_string=True,
left_title=" LEFT",
))
будет производить:
LEFT |
-------- | --------
a | a
c | c
| b
a | a
a | a
a | a
a | a
| d
a | a
a | a
e |
Вы можете использовать difflib.Differ для возврата одной последовательности строк с маркером в начале каждой строки, который описывает строку. Маркеры сообщают вам следующую информацию о линии:
Вы можете использовать эту информацию, чтобы решить, как отображать данные. Например, если маркер
, ставишь строчку и в левый и в правый виджеты. Если это
+
, вы можете поместить пустую строку слева и фактическую строку справа, показывая, что строка уникальна для текста справа. Так же,
-
означает, что линия уникальна слева.
Например, вы можете создать два текстовых виджета
t1
а также
t2
, один для левого и один для правого. Вы можете сравнить два файла, создав список строк для каждого, а затем передав их в
compare
метод разницы, а затем повторение результатов.
t1 = tk.Text(...)
t2 = tk.Text(...)
f1 = open("file1.txt", "r").readlines()
f2 = open("file2.txt", "r").readlines()
differ = difflib.Differ()
for line in differ.compare(f1, f2):
marker = line[0]
if marker == " ":
# line is same in both
t1.insert("end", line[2:])
t2.insert("end", line[2:])
elif marker == "-":
# line is only on the left
t1.insert("end", line[2:])
t2.insert("end", "\n")
elif marker == "+":
# line is only on the right
t1.insert("end", "\n")
t2.insert("end", line[2:])
Приведенный выше код игнорирует строки с маркером
?
поскольку это дополнительные строки, которые пытаются привлечь внимание к другим символам в предыдущей строке и на самом деле не являются частью ни одного из файлов. Вы можете использовать эту информацию, чтобы выделить отдельные символы, если хотите.
Как насчет этого?
>>> a = ['cat', 'dog', 'horse']
>>> b = ['cat', 'horse', 'chicken']
>>> comparison = list(l for l in difflib.Differ().compare(a,b) if not l.startswith('?'))
>>> left = [l[2:] if l.startswith((' ', '-')) else '' for l in comparison]
>>> right = [l[2:] if l.startswith((' ', '+')) else '' for l in comparison]
>>> left
['cat', 'dog', 'horse', '']
>>> right
['cat', '', 'horse', 'chicken']
Я пытался сделать файлы diff с difflib.context_diff:
diff = difflib.context_diff(fromlines, tolines, fromfile='file1.txt', tofile='file2.txt')
sys.stdout.writelines(diff)
В этом случае ваш вывод будет примерно таким:
*** file1.txt
--- file2.txt
***************
*** 1,6 ****
! aasdf
qwer
123
! poiu
! xzcv34
xzcv
--- 1,6 ----
! asdf
qwer
+ mnbv
123
! cvnn
xzcv
В этом случае вы сможете легко разделить каждый файл diff, но я не уверен, что вы будете удовлетворены выводом context_diff. Вы не упомянули, каким образом вы используете difflib.