difflib
— Помощники для вычисления дельт¶
Исходный код: Lib/difflib.py
Этот модуль предоставляет классы и функции для сравнения последовательностей. Его можно использовать, например, для сравнения файлов, и он может генерировать информацию о различиях в файлах в различных форматах, включая HTML, контекст и унифицированные различия. Для сравнения каталогов и файлов смотрите также модуль filecmp
.
- class difflib.SequenceMatcher
Это гибкий класс для сравнения пар последовательностей любого типа, при условии, что элементы последовательности равны hashable. Базовый алгоритм предшествует алгоритму, опубликованному в конце 1980-х годов Рэтклиффом и Обершелпом под гиперболическим названием «сопоставление гештальт-паттернов», и немного более причудлив по сравнению с ним. Идея состоит в том, чтобы найти самую длинную непрерывную совпадающую подпоследовательность, которая не содержит «ненужных» элементов; эти «ненужные» элементы в некотором смысле неинтересны, например, пустые строки или пробелы. (Обработка нежелательной информации является расширением алгоритма Ратклиффа и Обершелпа.) Затем та же идея рекурсивно применяется к фрагментам последовательностей слева и справа от соответствующей подпоследовательности. Это не приводит к минимальным последовательностям редактирования, но, как правило, приводит к совпадениям, которые «выглядят правильно» для людей.
** Хронометраж:** Основной алгоритм Ратклиффа-Обершелпа использует кубическое время в наихудшем случае и квадратичное время в ожидаемом случае.
SequenceMatcher
- квадратичное время в наихудшем случае, и его поведение в ожидаемом случае сложным образом зависит от того, сколько элементов имеют общие последовательности.; в лучшем случае время является линейным.Автоматическая эвристика нежелательной информации:
SequenceMatcher
поддерживает эвристику, которая автоматически рассматривает определенные элементы последовательности как нежелательные. Эвристика подсчитывает, сколько раз каждый отдельный элемент появляется в последовательности. Если количество дубликатов товара (после первого) составляет более 1% от всей последовательности и длина последовательности составляет не менее 200 товаров, этот товар помечается как «популярный» и рассматривается как нежелательный для целей сопоставления последовательности. Эту эвристику можно отключить, установив для аргументаautojunk
значениеFalse
при созданииSequenceMatcher
.Изменено в версии 3.2: Добавлен параметр автозапуск.
- class difflib.Differ¶
Это класс для сравнения последовательностей строк текста и создания удобочитаемых различий или дельт. Different использует
SequenceMatcher
как для сравнения последовательностей строк, так и для сравнения последовательностей символов в похожих (почти совпадающих) строках.Каждая строка дельты
Differ
начинается с двухбуквенного кода:Код
Значение
'- '
строка, уникальная для последовательности 1
'+ '
строка, уникальная для последовательности 2
' '
линия, общая для обеих последовательностей
'? '
строка, отсутствующая ни в одной из входных последовательностей
Строки, начинающиеся с «
?
», указывают на внутренние различия, которых не было ни в одной из введенных последовательностей. Эти строки могут сбивать с толку, если последовательности содержат символы табуляции.
- class difflib.HtmlDiff¶
Этот класс может быть использован для создания HTML-таблицы (или полного HTML-файла, содержащего таблицу), показывающей параллельное, построчное сравнение текста с выделением изменений между строками и внутри строки. Таблица может быть создана как в режиме полной, так и в режиме контекстных различий.
Конструктором для этого класса является:
- __init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)¶
Инициализирует экземпляр
HtmlDiff
.tabsize является необязательным аргументом ключевого слова для указания интервала между концами табуляции и по умолчанию равен
8
.wrapcolumn - необязательное ключевое слово для указания номера столбца, в котором строки прерываются и переносятся, по умолчанию используется
None
, в котором строки не переносятся.linejunk и charjunk являются необязательными ключевыми аргументами, передаваемыми в
ndiff()
(используютсяHtmlDiff
для создания параллельных HTML-различий). Значения и описания аргументов по умолчанию приведены в документацииndiff()
.
Следующие методы являются общедоступными:
- make_file(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5, *, charset='utf-8')¶
Сравнивает fromlines и tolines (списки строк) и возвращает строку, которая представляет собой полный HTML-файл, содержащий таблицу, показывающую построчные различия с выделенными изменениями между строками и внутри строки.
fromdesc и todesc являются необязательными аргументами ключевых слов для указания строк заголовка столбца from/to файла (по умолчанию используется пустая строка).
context и numlines являются необязательными аргументами ключевого слова. Установите для параметра context значение
True
, если необходимо отобразить контекстные различия, в противном случае по умолчанию используется значениеFalse
для отображения полных файлов. numlines по умолчанию имеет значение5
. Когда значение context равноTrue
, numlines управляет количеством контекстных строк, которые окружают выделенные различия. Когда значение context равноFalse
numlines определяет количество строк, которые отображаются перед выделением различий при использовании гиперссылок «next» (значение, равное нулю, приведет к тому, что гиперссылки «next» разместят следующую выделенную разницу в верхней части браузера без каких-либо начальных строк). контекст).Примечание
fromdesc и todesc интерпретируются как неэкранированный HTML и должны быть должным образом экранированы при получении входных данных из ненадежных источников.
Изменено в версии 3.5: кодировка Добавлен аргумент, содержащий только ключевое слово. Кодировка HTML-документа по умолчанию изменена с
'ISO-8859-1'
на'utf-8'
.
- make_table(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5)¶
Сравнивает fromlines и tolines (списки строк) и возвращает строку, которая представляет собой полную HTML-таблицу, показывающую построчные различия с выделенными изменениями между строками и внутри строки.
Аргументы для этого метода те же, что и для метода
make_file()
.
Tools/scripts/diff.py
является интерфейсом командной строки для этого класса и содержит хороший пример его использования.
- difflib.context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')¶
Сравните a и b (списки строк); верните дельту (a generator, генерирующую дельта-строки) в формате контекстной разницы.
Контекстные различия - это компактный способ отображения только тех строк, которые были изменены, плюс несколько строк контекста. Изменения отображаются в виде «до» и «после». Количество контекстных строк задается значением n, которое по умолчанию равно трем.
По умолчанию управляющие строки diff (те, что содержат
***
или---
) создаются с завершающей новой строкой. Это полезно для того, чтобы входные данные, созданные изio.IOBase.readlines()
, приводили к различиям, которые подходят для использования сio.IOBase.writelines()
, поскольку как входные, так и выходные данные имеют завершающие новые строки.Для входных данных, которые не содержат завершающих символов новой строки, установите для аргумента lineterm значение
""
, чтобы выходные данные были равномерно свободны от новой строки.Формат контекстных различий обычно содержит заголовок для имен файлов и времени изменения. Любой из них или все они могут быть указаны с помощью строк для fromfile, tofile, fromfiledate и tofiledate. Время внесения изменений обычно указывается в формате ISO 8601. Если это не указано, то строки по умолчанию будут пустыми.
>>> import sys >>> from difflib import * >>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] >>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', ... tofile='after.py')) *** before.py --- after.py *************** *** 1,4 **** ! bacon ! eggs ! ham guido --- 1,4 ---- ! python ! eggy ! hamster guido
Более подробный пример приведен в разделе Интерфейс командной строки для difflib.
- difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)¶
Возвращает список наилучших, «достаточно хороших» совпадений. word - это последовательность, для которой требуются близкие совпадения (обычно это строка), а possibilities - это список последовательностей, с которыми требуется сопоставить word (обычно это список строк).
Необязательный аргумент n (по умолчанию
3
) - это максимальное количество возвращаемых совпадений; n должно быть больше, чем0
.Необязательный аргумент cutoff (по умолчанию
0.6
) - это значение с плавающей запятой в диапазоне [0, 1]. Варианты, которые не соответствуют параметру word, игнорируются.Наилучшие (не более n) совпадения среди возможных вариантов отображаются в виде списка, отсортированного по степени сходства, сначала выбирается наиболее похожий.
>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy']) ['apple', 'ape'] >>> import keyword >>> get_close_matches('wheel', keyword.kwlist) ['while'] >>> get_close_matches('pineapple', keyword.kwlist) [] >>> get_close_matches('accept', keyword.kwlist) ['except']
- difflib.ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK)¶
Сравните a и b (списки строк); верните дельту в стиле
Differ
(a generator генерирует дельта-строки).Необязательные параметры ключевых слов linejunk и charjunk являются функциями фильтрации (или
None
):linejunk: Функция, которая принимает единственный строковый аргумент и возвращает значение true, если строка является ненужной, или значение false, если нет. Значение по умолчанию
None
. Существует также функция на уровне модуляIS_LINE_JUNK()
, которая отфильтровывает строки без видимых символов, за исключением не более одного символа-фунта ('#'
) – однако базовый классSequenceMatcher
выполняет динамический анализ того, какие строки являются настолько часто, что возникает шум, и это обычно работает лучше, чем при использовании данной функции.charjunk: функция, которая принимает символ (строку длиной 1) и возвращает, если символ является ненужным, или false, если нет. По умолчанию используется функция на уровне модуля
IS_CHARACTER_JUNK()
, которая отфильтровывает пробельные символы (пробел или табуляция; включать в нее новую строку - плохая идея!).Tools/scripts/ndiff.py
- это интерфейс командной строки для этой функции.>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True), ... 'ore\ntree\nemu\n'.splitlines(keepends=True)) >>> print(''.join(diff), end="") - one ? ^ + ore ? ^ - two - three ? - + tree + emu
- difflib.restore(sequence, which)¶
Возвращает одну из двух последовательностей, которые сгенерировали дельту.
Учитывая последовательность , полученную с помощью :meth:`Differ.compare` или :func:`ndiff`, извлеките строки, исходящие из файла 1 или 2 (параметр *which), удалив префиксы строк.
Пример:
>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True), ... 'ore\ntree\nemu\n'.splitlines(keepends=True)) >>> diff = list(diff) # materialize the generated delta into a list >>> print(''.join(restore(diff, 1)), end="") one two three >>> print(''.join(restore(diff, 2)), end="") ore tree emu
- difflib.unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')¶
Сравните a и b (списки строк); верните дельту (a generator, генерирующую дельта-строки) в унифицированном формате diff.
Унифицированные различия - это компактный способ отображения только тех строк, которые были изменены, плюс несколько строк контекста. Изменения отображаются в виде встроенного текста (вместо отдельных блоков «до» и «после»). Количество строк контекста задается значением n, которое по умолчанию равно трем.
По умолчанию управляющие строки diff (те, что содержат
---
,+++
, или@@
) создаются с завершающей новой строкой. Это полезно для того, чтобы входные данные, созданные изio.IOBase.readlines()
, приводили к различиям, которые подходят для использования сio.IOBase.writelines()
, поскольку как входные, так и выходные данные имеют завершающие новые строки.Для входных данных, которые не содержат завершающих символов новой строки, установите для аргумента lineterm значение
""
, чтобы выходные данные были равномерно свободны от новой строки.Унифицированный формат diff обычно содержит заголовок для имен файлов и времени изменения. Любой из них или все они могут быть указаны с помощью строк для fromfile, tofile, fromfiledate и tofiledate. Время внесения изменений обычно указывается в формате ISO 8601. Если это не указано, то строки по умолчанию будут пустыми.
>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n'] >>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n'] >>> sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py')) --- before.py +++ after.py @@ -1,4 +1,4 @@ -bacon -eggs -ham +python +eggy +hamster guido
Более подробный пример приведен в разделе Интерфейс командной строки для difflib.
- difflib.diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n')¶
Сравните a и b (списки объектов bytes), используя dfunc; получите последовательность дельта-строк (также байтов) в формате, возвращаемом dfunc. dfunc должен быть вызываемым, обычно либо
unified_diff()
, либоcontext_diff()
.Позволяет сравнивать данные с неизвестной или несогласованной кодировкой. Все входные данные, кроме n, должны быть объектами bytes, а не str. Работает путем преобразования всех входных данных (кроме n) в str без потерь и вызова
dfunc(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm)
. Выходные данные dfunc затем преобразуются обратно в байты, поэтому получаемые вами дельта-строки имеют те же неизвестные/несогласованные кодировки, что и a и b.Добавлено в версии 3.5.
- difflib.IS_LINE_JUNK(line)¶
Возвращает
True
для игнорируемых строк. Строка line игнорируется, если line пуста или содержит один'#'
, в противном случае она не игнорируется. Используется по умолчанию для параметра linejunk вndiff()
в более старых версиях.
- difflib.IS_CHARACTER_JUNK(ch)¶
Возвращает
True
для игнорируемых символов. Символ ch игнорируется, если ch является пробелом или символом табуляции, в противном случае он не игнорируется. Используется по умолчанию для параметра charjunk вndiff()
.
См.также
- Pattern Matching: The Gestalt Approach
Обсуждение аналогичного алгоритма Джоном У. Рэтклиффом и Д. Э. Метцнером. Это было опубликовано в Dr. Dobb’s Journal в июле 1988 года.
Объекты SequenceMatcher¶
В классе SequenceMatcher
есть этот конструктор:
- class difflib.SequenceMatcher(isjunk=None, a='', b='', autojunk=True)¶
Необязательный аргумент isjunk должен быть
None
(по умолчанию) или функция с одним аргументом, которая принимает элемент последовательности и возвращает значение true тогда и только тогда, когда элемент является «ненужным» и должен игнорироваться. ПередачаNone
для isjunk эквивалентна передачеlambda x: False
; другими словами, никакие элементы не игнорируются. Например, передача:lambda x: x in " \t"
если вы сравниваете строки как последовательности символов и не хотите синхронизировать их с пробелами или жесткими табуляциями.
Необязательные аргументы a и b являются сравниваемыми последовательностями; по умолчанию используются пустые строки. Элементы обеих последовательностей должны быть hashable.
Необязательный аргумент autojunk можно использовать для отключения автоматической эвристики нежелательной почты.
Изменено в версии 3.2: Добавлен параметр автозапуск.
Объекты SequenceMatcher получают три атрибута данных: bjunk - это набор элементов из b, для которых isjunk равен
True
; bpopular - это набор не мусорных элементов, которые эвристика считает популярными (если она не отключена); b2j это dict, отображающий остальные элементы b в список позиций, в которых они встречаются. Все три параметра сбрасываются всякий раз, когда b сбрасывается с помощьюset_seqs()
илиset_seq2()
.Добавлено в версии 3.2: Атрибуты bjunk и bpopular.
SequenceMatcher
объекты имеют следующие методы:- set_seqs(a, b)¶
Установите две последовательности для сравнения.
SequenceMatcher
вычисляет и кэширует подробную информацию о второй последовательности, поэтому, если вы хотите сравнить одну последовательность со многими последовательностями, используйтеset_seq2()
для однократного задания часто используемой последовательности и повторно вызывайтеset_seq1()
, по одному разу для каждой из следующих последовательностей. другие последовательности.- set_seq1(a)¶
Установите первую последовательность для сравнения. Вторая последовательность для сравнения не изменяется.
- set_seq2(b)¶
Установите вторую последовательность для сравнения. Первая последовательность для сравнения не изменяется.
- find_longest_match(alo=0, ahi=None, blo=0, bhi=None)¶
Найдите самый длинный совпадающий блок в
a[alo:ahi]
иb[blo:bhi]
.Если значение isjunk было опущено или
None
,find_longest_match()
возвращает(i, j, k)
таким образом, чтоa[i:i+k]
равноb[j:j+k]
, гдеalo <= i <= i+k <= ahi
иblo <= j <= j+k <= bhi
. Для всех(i', j', k')
, удовлетворяющих этим условиям, также выполняются дополнительные условияk >= k'
,i <= i'
, и еслиi == i'
,j <= j'
. Другими словами, из всех максимально совпадающих блоков верните тот, который начинается раньше всего в a, а из всех максимально совпадающих блоков, которые начинаются раньше всего в a, верните тот, который начинается раньше всего в b.>>> s = SequenceMatcher(None, " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) Match(a=0, b=4, size=5)
Если было указано значение isjunk, сначала определяется самый длинный соответствующий блок, как указано выше, но с дополнительным ограничением, чтобы в блоке не было ненужных элементов. Затем этот блок расширяется, насколько это возможно, путем сопоставления (только) ненужных элементов с обеих сторон. Таким образом, результирующий блок никогда не совпадает с мусором, за исключением случаев, когда идентичный мусор оказывается рядом с интересным совпадением.
Вот тот же пример, что и раньше, но с учетом того, что пробелы считаются ненужными. Это не позволяет
' abcd'
напрямую соответствовать' abcd'
в конце второй последовательности. Вместо этого может совпадать только'abcd'
, который совпадает с крайним левым'abcd'
во второй последовательности:>>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd") >>> s.find_longest_match(0, 5, 0, 9) Match(a=1, b=0, size=4)
Если ни один из блоков не совпадает, то возвращается
(alo, blo, 0)
.Этот метод возвращает named tuple
Match(a, b, size)
.Изменено в версии 3.9: Добавлены аргументы по умолчанию.
- get_matching_blocks()¶
Возвращает список троек, описывающих непересекающиеся совпадающие подпоследовательности. Каждая тройка имеет вид
(i, j, n)
и означает, чтоa[i:i+n] == b[j:j+n]
. Тройки монотонно увеличиваются в i и j.Последняя тройка является фиктивной и имеет значение
(len(a), len(b), 0)
. Это единственная тройка сn == 0
. Если(i, j, n)
и(i', j', n')
являются соседними тройками в списке, а вторая тройка не является последней в списке, тоi+n < i'
илиj+n < j'
; другими словами, соседние тройки всегда описывают несмежные равные блоки.>>> s = SequenceMatcher(None, "abxcd", "abcd") >>> s.get_matching_blocks() [Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]
- get_opcodes()¶
Возвращает список из 5 кортежей, описывающих, как превратить a в b. Каждый кортеж имеет вид
(tag, i1, i2, j1, j2)
. Первый кортеж имеет значениеi1 == j1 == 0
, а остальные кортежи имеют значение i1, равное i2 из предыдущего кортежа, и, аналогично, j1, равное предыдущему j2.Значения tag представляют собой строки со следующими значениями:
Ценность
Значение
'replace'
a[i1:i2]
следует заменить наb[j1:j2]
.'delete'
a[i1:i2]
должно быть удалено. Обратите внимание, что в этом случаеj1 == j2
.'insert'
b[j1:j2]
должно быть вставлено вa[i1:i1]
. Обратите внимание, что в этом случаеi1 == i2
.'equal'
a[i1:i2] == b[j1:j2]
(подпоследовательности равны).Например:
>>> a = "qabxcd" >>> b = "abycdf" >>> s = SequenceMatcher(None, a, b) >>> for tag, i1, i2, j1, j2 in s.get_opcodes(): ... print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format( ... tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) delete a[0:1] --> b[0:0] 'q' --> '' equal a[1:3] --> b[0:2] 'ab' --> 'ab' replace a[3:4] --> b[2:3] 'x' --> 'y' equal a[4:6] --> b[3:5] 'cd' --> 'cd' insert a[6:6] --> b[5:6] '' --> 'f'
- get_grouped_opcodes(n=3)¶
Возвращает generator групп, содержащих до n строк контекста.
Начиная с групп, возвращаемых с помощью
get_opcodes()
, этот метод разбивает меньшие кластеры изменений и устраняет промежуточные диапазоны, в которых изменений нет.Группы возвращаются в том же формате, что и
get_opcodes()
.
- ratio()¶
Возвращает меру сходства последовательностей в виде числа с плавающей точкой в диапазоне [0, 1].
Где T - общее количество элементов в обеих последовательностях, а M - количество совпадений, это 2,0*M / T. Обратите внимание, что это
1.0
, если последовательности идентичны, и0.0
, если у них нет ничего общего.Это дорогостоящее вычисление, если
get_matching_blocks()
илиget_opcodes()
еще не были вызваны, и в этом случае вы можете сначала попробоватьquick_ratio()
илиreal_quick_ratio()
, чтобы получить верхнюю границу.Примечание
Внимание: Результат вызова
ratio()
может зависеть от порядка аргументов. Например:>>> SequenceMatcher(None, 'tide', 'diet').ratio() 0.25 >>> SequenceMatcher(None, 'diet', 'tide').ratio() 0.5
Три метода, которые возвращают отношение совпадения к общему количеству символов, могут давать разные результаты из-за различных уровней аппроксимации, хотя quick_ratio()
и real_quick_ratio()
всегда по меньшей мере равны ratio()
:
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75
>>> s.quick_ratio()
0.75
>>> s.real_quick_ratio()
1.0
Примеры последовательностей¶
В этом примере сравниваются две строки, в которых пробелы считаются «ненужными».:
>>> s = SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
ratio()
возвращает значение с плавающей точкой в [0, 1], измеряющее сходство последовательностей. Как правило, значение ratio()
больше 0,6 означает, что последовательности почти совпадают:
>>> print(round(s.ratio(), 3))
0.866
Если вас интересует только совпадение последовательностей, get_matching_blocks()
будет удобно:
>>> for block in s.get_matching_blocks():
... print("a[%d] and b[%d] match for %d elements" % block)
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements
Обратите внимание, что последний кортеж, возвращаемый get_matching_blocks()
, всегда является фиктивным, (len(a), len(b), 0)
, и это единственный случай, когда последний элемент кортежа (количество совпадающих элементов) равен 0
.
Если вы хотите знать, как изменить первую последовательность на вторую, используйте get_opcodes()
:
>>> for opcode in s.get_opcodes():
... print("%6s a[%d:%d] b[%d:%d]" % opcode)
equal a[0:8] b[0:8]
insert a[8:8] b[8:17]
equal a[8:29] b[17:38]
См.также
Функция
get_close_matches()
в этом модуле, которая показывает, как простой код, основанный наSequenceMatcher
, может быть использован для выполнения полезной работы.Simple version control recipe для небольшого приложения, созданного с помощью
SequenceMatcher
.
Разные объекты¶
Обратите внимание, что Differ
-сгенерированные значения delta не претендуют на то, чтобы быть минимальными различиями. Напротив, минимальные различия часто противоречат интуиции, потому что они синхронизируются везде, где это возможно, иногда случайно совпадают с интервалом в 100 страниц. Ограничение точек синхронизации смежными совпадениями сохраняет некоторое представление о локальности, но иногда приводит к увеличению размера различий.
В классе Differ
есть этот конструктор:
- class difflib.Differ(linejunk=None, charjunk=None)
Необязательные параметры ключевых слов linejunk и charjunk предназначены для функций фильтрации (или
None
):linejunk: Функция, которая принимает единственный строковый аргумент и возвращает значение true, если строка является ненужной. Значение по умолчанию
None
, что означает, что ни одна строка не считается ненужной.charjunk: функция, которая принимает односимвольный аргумент (строку длиной 1) и возвращает значение true, если символ является ненужным. Значение по умолчанию
None
, что означает, что ни один символ не считается ненужным.Эти функции фильтрации нежелательной почты ускоряют поиск различий и не приводят к игнорированию каких-либо отличающихся строк или символов. Для получения более подробной информации ознакомьтесь с описанием параметра isjunk для метода
find_longest_match()
.Differ
объекты используются (генерируются дельты) с помощью одного метода:- compare(a, b)¶
Сравните две последовательности линий и сгенерируйте дельту (последовательность линий).
Каждая последовательность должна содержать отдельные однострочные строки, заканчивающиеся символами новой строки. Такие последовательности могут быть получены с помощью метода
readlines()
для файлоподобных объектов. Сгенерированная разность также состоит из строк, заканчивающихся новой строкой, готовых к печати как есть с помощью методаwritelines()
объекта, подобного файлу.
Другой пример¶
В этом примере сравниваются два текста. Сначала мы настраиваем тексты - последовательности отдельных однострочных строк, заканчивающихся символами новой строки (такие последовательности также можно получить с помощью метода readlines()
для файлоподобных объектов).:
>>> text1 = ''' 1. Beautiful is better than ugly.
... 2. Explicit is better than implicit.
... 3. Simple is better than complex.
... 4. Complex is better than complicated.
... '''.splitlines(keepends=True)
>>> len(text1)
4
>>> text1[0][-1]
'\n'
>>> text2 = ''' 1. Beautiful is better than ugly.
... 3. Simple is better than complex.
... 4. Complicated is better than complex.
... 5. Flat is better than nested.
... '''.splitlines(keepends=True)
Затем мы создаем экземпляр объекта Different:
>>> d = Differ()
Обратите внимание, что при создании экземпляра объекта Differ
мы можем передавать функции для фильтрации «ненужных» строк и символов. Подробности смотрите в конструкторе Differ()
.
Наконец, мы сравниваем эти два:
>>> result = list(d.compare(text1, text2))
result
- это список строк, так что давайте оформим его красиво:
>>> from pprint import pprint
>>> pprint(result)
[' 1. Beautiful is better than ugly.\n',
'- 2. Explicit is better than implicit.\n',
'- 3. Simple is better than complex.\n',
'+ 3. Simple is better than complex.\n',
'? ++\n',
'- 4. Complex is better than complicated.\n',
'? ^ ---- ^\n',
'+ 4. Complicated is better than complex.\n',
'? ++++ ^ ^\n',
'+ 5. Flat is better than nested.\n']
В виде одной многострочной строки это выглядит следующим образом:
>>> import sys
>>> sys.stdout.writelines(result)
1. Beautiful is better than ugly.
- 2. Explicit is better than implicit.
- 3. Simple is better than complex.
+ 3. Simple is better than complex.
? ++
- 4. Complex is better than complicated.
? ^ ---- ^
+ 4. Complicated is better than complex.
? ++++ ^ ^
+ 5. Flat is better than nested.
Интерфейс командной строки для difflib¶
В этом примере показано, как использовать difflib для создания утилиты, подобной diff
. Она также содержится в исходном коде Python как Tools/scripts/diff.py
.