# `difflib` — Helpers for computing deltas

Código fuente: Lib/difflib.py

This module provides classes and functions for comparing sequences. Most of them compare sequences of text lines (for example lists of strings, or file objects) and produce diffs – reports on the differences. Diffs can be produced in in various formats, including HTML and context and unified diffs – formats produced by tools like diff and git diff.

Comparisons are done using a matching algorithm implemented in `SequenceMatcher` – a flexible class for comparing pairs of sequences of any type, not just text, so long as the sequence elements are hashable.

## Junk heuristic

`difflib` uses a junk heuristic: some items are deemed to be junk, and ignored when searching for similarities. Ideally, these are uninteresting or common items, such as blank lines or whitespace.

This heuristic can speed the algorithm up (because it reduces the number of possible combinations) and it can produce results that are more understandable for humans (typically breaking on whitespace). But it can also cause pathological cases:

- Inappropriately chosen junk items can cause an unexpectedly large (but still correct) result.

- The default heuristic is asymmetric: only the second sequence is inspected when determining what is considered junk, so comparing A to B can give different results than comparing B to A and reversing the result.

By default, if the second input sequence is at least 200 items long, items that account for more than 1% it are considered junk.

Depending on your data, you should consider turning this heuristic off (setting `SequenceMatcher`’s autojunk argument to to `False`) or tuning it (using the isjunk argument, perhaps to one of the predefined functions).

## The `difflib` algorithm

The algorithm used in `SequenceMatcher` predates, and is a little fancier than, an algorithm published in the late 1980s by Ratcliff and Obershelp under the hyperbolic name «gestalt pattern matching.» The idea is to find the longest contiguous subsequence common to both inputs, then recursively handle the pieces of the sequences to the left and to the right of the matching subsequence.

Ver también

Pattern Matching: The Gestalt Approach

  Discussion of a similar algorithm by John W. Ratcliff and D. E. Metzener. This was published in Dr. Dobb’s Journal in July, 1988.

As an extension to the Ratcliff and Obershelp algorithm, `difflib` searches for the longest junk-free contiguous subsequence. See the Junk heuristic section for details.

Detalles de implementación de CPython: Timing

The basic Ratcliff-Obershelp algorithm is cubic time in the worst case and quadratic time in the expected case. `difflib`’s algorithm is quadratic time for the worst case and has expected-case behavior dependent in a complicated way on how many elements the sequences have in common; best case time is linear.

## Diff generation

class difflib.Differ

  Esta clase se utiliza para comparar secuencias de lineas de texto y producir diferencias o deltas en una forma legible por humanos. Differ usa `SequenceMatcher` tanto para comparar secuencias de lineas, como para comparar secuencias de caracteres entre lineas similares.

  Cada linea de un delta de `Differ` comienza con un código de dos letras:

  Código | Significado
  --- | ---
  `'- '` | línea única para la secuencia 1
  `'+ '` | línea única para la secuencia 2
  `' '` | línea común a ambas secuencias
  `'? '` | línea ausente en todas las secuencias de entrada

  Lines beginning with “`?`” attempt to guide the eye to intraline differences, and were not present in either input sequence. These lines can be confusing if the sequences contain whitespace characters, such as spaces, tabs or line breaks.

  Note that `Differ`-generated deltas make no claim to be minimal diffs. To the contrary, minimal diffs are often counter-intuitive for humans, because they synch up anywhere possible, sometimes at accidental matches 100 pages apart. Restricting synch points to contiguous matches preserves some notion of locality, at the occasional cost of producing a longer diff.

  La clase `Differ` tiene el siguiente constructor:

  __init__(linejunk=None, charjunk=None)

    Parámetros de palabra clave opcionales linejunk y charjunk son para funciones de filtrado (o `None`):

    linejunk: Una función que acepta una sola cadena de texto como argumento y retorna verdadero si la cadena de texto es un elemento no deseado. Su valor por defecto es `None`, lo que significa que ninguna línea es considerada no deseada.

    charjunk: Una función que acepta un solo carácter como argumento (una cadena de caracteres de longitud 1) y retorna verdadero si el carácter es un elemento no deseado. Su valor por defecto es `None`, lo que significa que ningún carácter es considerado no deseado.

    Estas funciones de elementos no deseados aceleran la coincidencia para encontrar diferencies y no hacen que se ignoren líneas o caracteres diferentes. Lea la descripción del parámetro isjunk en el método `find_longest_match()` para una explicación mas detallada.

  Los objetos `Differ` son usados (una vez generados los deltas) mediante un solo método:

  compare(a, b)

    Compara dos secuencias de líneas y genera el delta correspondiente (una secuencia de líneas).

    Each sequence must contain individual single-line strings ending with newlines. Such sequences can be obtained from the `readlines()` method of file-like objects. The generated delta also consists of newline-terminated strings, ready to be printed as-is via the `writelines()` method of a file-like object.

class difflib.HtmlDiff

  Esta clase puede ser usada para crear una tabla HTML (o un archivo HTML completo que contenga la tabla) mostrando comparaciones lado a lado y linea por linea del texto, con cambios interlineales e intralineales. La tabla se puede generar en modo de diferencia completa o contextual.

  Advertencia

  The trailing newlines get stripped before the diff, so the result can be incomplete. See gh-71896 for details.

  El constructor de esta clase es:

  __init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)

    Inicializa una instancia de `HtmlDiff`.

    tabsize es un argumento por palabra clave opcional para especificar el espaciado de tabulación. Su valor predeterminado es `8`.

    wrapcolumn es un argumento por palabra clave opcional para especificar el número de columnas donde las lineas serán divididas y ajustadas al ancho de columna, su valor por defecto es `None`, donde las lineas no son ajustadas.

    linejunk y charjunk son argumentos por palabra clave opcionales que serán pasados a `ndiff()` (que es utilizado por `HtmlDiff` para generar las diferencias lado a lado en HTML). Refiérase a la documentación de `ndiff()` para conocer los detalles y valores por defecto de sus argumentos.

  Los siguientes métodos son públicos:

  make_file(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5, *, charset='utf-8')

    Compara fromlines y tolines (listas de cadenas de texto) y retorna una cadena de caracteres que representa un archivo HTML completo que contiene una tabla mostrando diferencias línea por línea del texto con cambios interlineales e intralineales resaltados.

    fromdesc y todesc son argumentos por palabra clave opcionales para especificar los encabezados de las columnas desde fromdesc hasta todesc en el archivo (ambas cadenas están vacías por defecto).

    context y numlines son parámetros opcionales. Establezca context como `True` para mostrar diferencias contextuales, de lo contrario su valor por defecto es `False` que muestra los archivos completos. El valor por defecto de numlines es `5`. Cuando context es `True`, numlines controla el número de lineas de contexto que rodean las diferencias resaltadas. Cuando context es `False`, numlines controla el número de líneas que se muestran antes de una diferencia resaltada cuando se usan los hipervínculos «next» (un valor de cero produce que los hipervínculos «next» ubiquen el siguiente resaltado en la parte superior del navegador, sin ningún contexto principal).

    Nota

    fromdesc y todesc se interpretan como HTML no escapado y se deben escapar correctamente si los datos son recibidos de fuentes no confiables.

    Distinto en la versión 3.5: Se agregó el argumento sólo de palabra clave charset. La codificación de caracteres por defecto para documentos HTML se cambió de `'ISO-8859-1'` a `'utf-8'`.

  make_table(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5)

    Compara fromlines y tolines (listas de cadenas de texto) y retorna una cadena de caracteres que representa una tabla HTML mostrando comparaciones lado a lado y línea por línea del texto con cambios interlineales e intralineales.

    Los argumentos para este método son los mismos que los del método `make_file()`.

difflib.context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')

  Compara a y b (listas de cadenas de texto); retorna un delta (un generator que genera las lineas delta) en formato de diferencias de contexto.

  El formato de diferencias de contexto es una forma compacta de mostrar solamente las líneas que fueron modificadas y algunas líneas adicionales de contexto. Los cambios son mostrados utilizando el estilo antes/después. El número de líneas de contexto es determinado por n, cuyo valor por defecto es `3`.

  Por defecto, las líneas de control (aquellas que comienzan con `***` o `---`) son creadas con una línea nueva. Esto es de ayuda para que las entradas creadas por `io.IOBase.readlines()` generen diferencias que puedan ser utilizadas con `io.IOBase.writelines()` ya que ambas, la entrada y la salida, tienen líneas nuevas al final.

  Para entradas que no tienen nuevas líneas finales, establezca el argumento lineterm como `""` de forma que la salida sea uniforme y libre de nuevas líneas.

  El formato de diferencias de contexto normalmente tiene un encabezado para nombres de archivos y tiempos de modificaciones. Alguno o todos estos debe ser especificado utilizando las cadenas de texto para fromfile, tofile, fromfiledate y tofiledate. Los tiempos de modificación son normalmente expresados en formato ISO 8601. Si no es especificado las cadenas por defecto son espacios en blanco.

      >>> 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

  Vea Una interfaz de línea de comandos para difflib para un ejemplo mas detallado.

difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)

  Retorna una lista de las mejores coincidencias «lo suficientemente buenas». word es una secuencia para la cual coincidencias cercanas son deseadas (usualmente una cadena de texto), y possibilities es una lista de secuencias contra la cual se compara word (comúnmente una lista de cadenas de caracteres).

  Argumento opcional n (por defecto `3`) es el máximo número de coincidencias cercanas a retornar; n debe ser mayor que `0`.

  Argumento opcional cutoff (por defecto `0.6`) es un flotante en el rango [0, 1]. Las posibilidades que no alcanzan un puntaje al menos similar al de word son ignoradas.

  Las mejores (no mas de n) coincidencias entre las posibilidades son retornadas en una lista, ordenadas por similitud de puntaje, las mas similares primero.

      >>> 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)

  Compara a y b (listas de cadenas de texto); retorna un delta del estilo `Differ` (un generator que genera los deltas de las líneas).

  Parámetros de palabra clave opcional linejunk y charjunk son funciones de filtrado (o `None`):

  linejunk: A function that accepts a single string argument, and returns true if the string is junk, or false if not. The default is `None`. There is also a module-level function `IS_LINE_JUNK()`, which filters out lines without visible characters, except for at most one hash character (`'#'`) – however the underlying `SequenceMatcher` class does a dynamic analysis of which lines are so frequent as to constitute noise, and this usually works better than using this function.

  charjunk: Una función que acepta un carácter (una cadena de caracteres de longitud 1) como argumento, y retorna True si el carácter es un elemento no deseado, o False si no lo es. El valor por defecto es una función a nivel del módulo `IS_CHARACTER_JUNK()`, que filtra caracteres de espacios en blanco (un espacio en blanco o tabulación; es una mala idea incluir saltos de lineas en esto!)

      >>> 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)

  Retorna uno de las dos secuencias que generaron un delta.

  Dada una sequence producida por `Differ.compare()` o `ndiff()`, extrae las líneas originadas por el archivo 1 o 2 (parámetro which), quitando los prefijos de la línea.

  Ejemplo:

      >>> 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', *, color=False)

  Compara a y b (listas de cadenas de caracteres); retorna un delta (un generator que genera los delta de líneas) en formato de diferencias unificado.

  Las diferencias unificadas son una forma compacta de mostrar sólo las líneas que presentan cambios y algunas líneas de contexto adicionales. Los cambios son mostrados en una sola línea (en lugar de bloques separados antes y después). El número de líneas de contexto se establece mediante n, cuyo valor por defecto es tres.

  Por defecto, las líneas de control de diferencias (aquellas con `---`, `+++`, o `@@`) son creadas con un salto de línea nuevo. Esto es de ayuda para que las entradas creadas por `io.IOBase.readlines()` generen diferencias que puedan ser utilizadas con `io.IOBase.writelines()` ya que ambas, la entrada y la salida, tienen líneas nuevas al final.

  Para entradas que no tienen nuevas líneas finales, establezca el argumento lineterm como `""` de forma que la salida sea uniforme y libre de nuevas líneas.

  Set color to `True` to enable output in color, similar to git diff --color. Even if enabled, it can be controlled using environment variables.

  The unified diff format normally has a header for filenames and modification times. Any or all of these may be specified using strings for fromfile, tofile, fromfiledate, and tofiledate. The modification times are normally expressed in the ISO 8601 format. If not specified, the strings default to blanks.

      >>> 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

  Vea Una interfaz de línea de comandos para difflib para un ejemplo mas detallado.

  Distinto en la versión 3.15: Added the color parameter.

difflib.diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n')

  Compara a y b (listas de objetos de bytes) usando dfunc; produce una secuencia de líneas delta (también bytes) en el formato retornado por dfunc. dfunc debe ser invocable, comúnmente cualquiera de `unified_diff()` o `context_diff()`.

  Permite comparar datos con codificación desconocida o inconsistente. Todas las entradas, excepto n, deben ser objetos de bytes, no cadenas de texto. Funciona convirtiendo sin pérdidas todas las entradas (excepto n) a cadenas de texto, e invoca `dfunc(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm)`. La salida de dfunc es entonces convertida nuevamente a bytes, de forma que las líneas delta que son recibidas tienen la misma codificación desconocida/inconsistente que a y b.

  Added in version 3.5.

## Junk definition functions

difflib.IS_LINE_JUNK(line)

  Retorna `True` para líneas que deben ser ignoradas. La línea line es ignorada si line es un espacio vacío o contiene un solo `'#'`, en cualquier otro caso no es ignorado. Es usado como valor por defecto para el parámetro linejunk por `ndiff()` en versiones anteriores.

difflib.IS_CHARACTER_JUNK(ch)

  Retorna `True` para los caracteres que deben ser ignorados. El carácter ch es ignorado si ch es un espacio en blanco o tabulación, en cualquier otro caso no es ignorado. Es utilizado como valor por defecto para el parámetro charjunk en `ndiff()`.

## SequenceMatcher objects

class difflib.SequenceMatcher(isjunk=None, a='', b='', autojunk=True)

  El argumento opcional isjunk debe ser `None` (que es su valor por defecto) o una función de un solo argumento que reciba un elemento de la secuencia y retorne verdadero si y solo si el elemento es no deseado y deba ser ignorado. Pasar el argumento isjunk como `None` es equivalente a pasar `lambda x: False`; en otras palabras, ningún elemento es ignorado. Por ejemplo, pasar:

      lambda x: x in " \t"

  si se están comparando líneas como secuencias de caracteres, y no se quiere sincronizar en espacios blancos o tabulaciones.

  Los argumentos opcionales a y b son las secuencias a comparar; ambos tienen como valor por defecto una cadena de texto vacía. Los elementos de ambas secuencias deben ser hashable.

  El argumento opcional autojunk puede ser usado para deshabilitar la heurística automática de elementos no deseados.

  Distinto en la versión 3.2: Added the autojunk parameter.

  Los objetos SequenceMatcher reciben tres atributos: bjunk es el conjunto de elementos de b para los cuales isjunk es `True`; bpopular es el set de elementos que no son basura considerados populares por la heurística (si no es que fue deshabilitada); b2j es un diccionario que mapea elementos de b a una lista de posiciones donde estos ocurren. Los tres atributos son reseteados cuando b es reseteado mediante `set_seqs()` o `set_seq2()`.

  Added in version 3.2: Los atributos bjunk y bpopular.

  Los objetos `SequenceMatcher` tienen los siguientes métodos:

  set_seqs(a, b)

    Establece las dos secuencias a ser comparadas.

  `SequenceMatcher` calcula y almacena información detallada sobre la segunda secuencia, con lo cual si quieres comparar una secuencia contra muchas otras, usa `set_seq2()` para establecer la secuencia común una sola vez y llamar `set_seq1()` repetidamente, una vez por cada una de las otras secuencias.

  set_seq1(a)

    Establece la primer secuencia a ser comparada. La segunda secuencia a ser comparada no es modificada.

  set_seq2(b)

    Establece la segunda secuencia a ser comparada. La primera secuencia a ser comparada no es modificada.

  find_longest_match(alo=0, ahi=None, blo=0, bhi=None)

    Encuentra el bloque de coincidencia mas largo en `a[alo:ahi]` y `b[blo:bhi]`.

    Si isjunk fue omitido o es `None`, `find_longest_match()` retorna `(i, j, k)` tal que `a[i:i+k]` es igual a `b[j:j+k]`, donde `alo <= i <= i+k <= ahi` y `blo <= j <= j+k <= bhi`. Para todo `(i', j', k')` cumpliendo esas condiciones, las condiciones adicionales `k >= k'`, `i <= i'`, y si `i == i'`, `j <= j'` también se cumplen. En otras palabras, de todos los bloques coincidentes máximos, retorna aquel que comienza antes en a, y de todos esos bloques coincidentes máximos que comienzan antes en a, retorna aquel que comienza antes en b.

        >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
        >>> s.find_longest_match(0, 5, 0, 9)
        Match(a=0, b=4, size=5)

    Si se porporcionó isjunk, primero se determina el bloque coincidente mas largo como fue indicado anteriormente, pero con la restricción adicional de que no aparezca ningún elemento no deseado en el bloque. Entonces, ese bloque se extiende tan lejos como sea posible haciendo coincidir (solo) elementos no deseados de ambos lados. Por lo tanto, el bloque resultante nunca hará coincidir ningún elemento no deseado, excepto que un elemento no deseado idéntico pase a ser adyacente a una coincidencia interesante.

    Este es el mismo ejemplo que el mostrado anteriormente, pero considerando elementos en blanco como no deseados. Esto previene que `' abcd'` sea coincidente con `'abcd'` en el final de la segunda secuencia directamente. En cambio, sólo el `'abcd'` puede coincidir, y coincide con el `'abcd'` que se encuentre mas a la izquierda en la segunda secuencia:

        >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
        >>> s.find_longest_match(0, 5, 0, 9)
        Match(a=1, b=0, size=4)

    Si no coincide ningún bloque, esto retorna `(alo, blo, 0)`.

    Este método retorna un named tuple `Match(a, b, size)`.

    Distinto en la versión 3.9: Se agregaron argumentos predeterminados.

  get_matching_blocks()

    Retorna una lista de triplas (tuplas de tres elementos) describiendo subsecuencias coincidentes no superpuestas. Cada tripla sigue el formato `(i, j, n)`, y significa que `a[i:i+n] == b[j:j+n]`. Las triplas son monótonamente crecientes en i y j.

    La última tripla es un objeto ficticio (dummy), y tiene el valor `(len(a), len(b), 0)`. Es la única tripla con `n == 0`. Si `(i, j, n)` y `(i', j', n')` son triplas adyacentes en la lista, y la segunda no es el último elemento de la lista, entonces `i+n < i'` o `j+n < j'`; en otras palabras, las triplas adyacentes describen bloques iguales no adyacentes.

        >>> 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()

    Retorna una lista de quíntuplas (tuplas de cinco elementos) describiendo como convertir a en b. Cada tupla tiene la forma `(tag, i1, i2, j1, j2)`. En la primer tupla se cumple que `i1 == j1 == 0`, y las tuplas restantes tienen i1 igual al i2 de la tupla precedente, y de igual manera, j1 igual al j2 de la tupla anterior.

    Los valores de tag son cadenas de caracteres, con el siguiente significado:

    Valor | Significado
    --- | ---
    `'replace'` | `a[i1:i2]` debe ser reemplazado por `b[j1:j2]`.
    `'delete'` | `a[i1:i2]` debe ser eliminado. Nótese que en este caso `j1 == j2`.
    `'insert'` | `b[j1:j2]` debe ser insertado en `a[i1:i1]`. Nótese que en este caso `i1 == i2`.
    `'equal'` | `a[i1:i2] == b[j1:j2]` (las subsecuencias son iguales).

    Por ejemplo:

        >>> 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)

    Retorna un generator de grupos de hasta n líneas de contexto.

    Empezando con los grupos retornados por `get_opcodes()`, este método separa grupos con cambios menores y elimina los rangos intermedios que no tienen cambios.

    Los grupos son retornados en el mismo formato que `get_opcodes()`.

  ratio()

    Retorna una medida de la similitud de las secuencias como un flotante en el rango [0, 1].

    Donde T es el número total de elementos en ambas secuencias y M es el número de coincidencias, esto es 2.0*M / T. Nótese que esto es `1.0` si las secuencias son idénticas y `0.0` si no tienen nada en común.

    Esto es computacionalmente costoso si `get_matching_blocks()` o `get_opcodes()` no fueron ejecutados, in tal caso deberías considerar primero `quick_ratio()` o `real_quick_ratio()` para obtener un límite superior.

  quick_ratio()

    Retorna un límite superior en `ratio()` relativamente rápido.

  real_quick_ratio()

    Retorna un límite superior en `ratio()` muy rápido.

The three methods that return the ratio of matching to total characters can give different results due to differing levels of approximation, although `quick_ratio()` and `real_quick_ratio()` are always at least as large as `ratio()`:

    >>> s = SequenceMatcher(None, "abcd", "bcde")
    >>> s.ratio()
    0.75
    >>> s.quick_ratio()
    0.75
    >>> s.real_quick_ratio()
    1.0

## Examples

### SequenceMatcher examples

Este ejemplo compara dos cadenas de texto, considerando los espacios en blanco como caracteres no deseados:

    >>> s = SequenceMatcher(lambda x: x == " ",
    ...                     "private Thread currentThread;",
    ...                     "private volatile Thread currentThread;")

`ratio()` returns a float in [0, 1], measuring the similarity of the sequences. As a rule of thumb, a `ratio()` value over 0.6 means the sequences are close matches:

    >>> print(round(s.ratio(), 3))
    0.866

If you’re only interested in where the sequences match, `get_matching_blocks()` is handy:

    >>> 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

Note that the last tuple returned by `get_matching_blocks()` is always a dummy, `(len(a), len(b), 0)`, and this is the only case in which the last tuple element (number of elements matched) is `0`.

If you want to know how to change the first sequence into the second, use `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]

Ver también

- La función `get_close_matches()` en este módulo que muestra lo simple que es el código que construye `SequenceMatcher` puede ser utilizada para hacer un trabajo útil.

- Simple version control recipe for a small application built with `SequenceMatcher`.

### Differ example

This example compares two texts. First we set up the texts, sequences of individual single-line strings ending with newlines (such sequences can also be obtained from the `readlines()` method of file-like objects):

    >>> 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)

Luego instanciamos el objeto Differ:

    >>> d = Differ()

Nótese que cuando instanciamos un objeto `Differ` deberíamos pasar funciones para filtrar lineas y caracteres no deseados. Consulte el constructor de `Differ()` para mas detalles.

Finalmente, comparamos las dos:

    >>> result = list(d.compare(text1, text2))

`result` is a list of strings, so let’s pretty-print it:

    >>> 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']

As a single multi-line string it looks like this:

    >>> 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.

### Una interfaz de línea de comandos para `difflib`

This example shows how to use difflib to create a `diff`-like utility.

    """ Command-line interface to difflib.py providing diffs in four formats:

    * ndiff:    lists every line and highlights interline changes.
    * context:  highlights clusters of changes in a before/after format.
    * unified:  highlights clusters of changes in an inline format.
    * html:     generates side by side comparison with change highlights.

    """

    import sys, os, difflib, argparse
    import datetime as dt

    def file_mtime(path):
        t = dt.datetime.fromtimestamp(os.stat(path).st_mtime,
                                      dt.timezone.utc)
        return t.astimezone().isoformat()

    def main():

        parser = argparse.ArgumentParser()
        parser.add_argument('-c', action='store_true', default=False,
                            help='Produce a context format diff (default)')
        parser.add_argument('-u', action='store_true', default=False,
                            help='Produce a unified format diff')
        parser.add_argument('-m', action='store_true', default=False,
                            help='Produce HTML side by side diff '
                                 '(can use -c and -l in conjunction)')
        parser.add_argument('-n', action='store_true', default=False,
                            help='Produce a ndiff format diff')
        parser.add_argument('-l', '--lines', type=int, default=3,
                            help='Set number of context lines (default 3)')
        parser.add_argument('fromfile')
        parser.add_argument('tofile')
        options = parser.parse_args()

        n = options.lines
        fromfile = options.fromfile
        tofile = options.tofile

        fromdate = file_mtime(fromfile)
        todate = file_mtime(tofile)
        with open(fromfile) as ff:
            fromlines = ff.readlines()
        with open(tofile) as tf:
            tolines = tf.readlines()

        if options.u:
            diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
        elif options.n:
            diff = difflib.ndiff(fromlines, tolines)
        elif options.m:
            diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n)
        else:
            diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)

        sys.stdout.writelines(diff)

    if __name__ == '__main__':
        main()

### ndiff example

This example shows how to use `difflib.ndiff()`.

    """ndiff [-q] file1 file2
        or
    ndiff (-r1 | -r2) < ndiff_output > file1_or_file2

    Print a human-friendly file difference report to stdout.  Both inter-
    and intra-line differences are noted.  In the second form, recreate file1
    (-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.

    In the first form, if -q ("quiet") is not specified, the first two lines
    of output are

    -: file1
    +: file2

    Each remaining line begins with a two-letter code:

        "- "    line unique to file1
        "+ "    line unique to file2
        "  "    line common to both files
        "? "    line not present in either input file

    Lines beginning with "? " attempt to guide the eye to intraline
    differences, and were not present in either input file.  These lines can be
    confusing if the source files contain tab characters.

    The first file can be recovered by retaining only lines that begin with
    "  " or "- ", and deleting those 2-character prefixes; use ndiff with -r1.

    The second file can be recovered similarly, but by retaining only "  " and
    "+ " lines; use ndiff with -r2; or, on Unix, the second file can be
    recovered by piping the output through

        sed -n '/^[+ ] /s/^..//p'
    """

    __version__ = 1, 7, 0

    import difflib, sys

    def fail(msg):
        out = sys.stderr.write
        out(msg + "\n\n")
        out(__doc__)
        return 0

    # open a file & return the file object; gripe and return 0 if it
    # couldn't be opened
    def fopen(fname):
        try:
            return open(fname)
        except IOError as detail:
            return fail("couldn't open " + fname + ": " + str(detail))

    # open two files & spray the diff to stdout; return false iff a problem
    def fcompare(f1name, f2name):
        f1 = fopen(f1name)
        f2 = fopen(f2name)
        if not f1 or not f2:
            return 0

        a = f1.readlines(); f1.close()
        b = f2.readlines(); f2.close()
        for line in difflib.ndiff(a, b):
            print(line, end=' ')

        return 1

    # crack args (sys.argv[1:] is normal) & compare;
    # return false iff a problem

    def main(args):
        import getopt
        try:
            opts, args = getopt.getopt(args, "qr:")
        except getopt.error as detail:
            return fail(str(detail))
        noisy = 1
        qseen = rseen = 0
        for opt, val in opts:
            if opt == "-q":
                qseen = 1
                noisy = 0
            elif opt == "-r":
                rseen = 1
                whichfile = val
        if qseen and rseen:
            return fail("can't specify both -q and -r")
        if rseen:
            if args:
                return fail("no args allowed with -r option")
            if whichfile in ("1", "2"):
                restore(whichfile)
                return 1
            return fail("-r value must be 1 or 2")
        if len(args) != 2:
            return fail("need 2 filename args")
        f1name, f2name = args
        if noisy:
            print('-:', f1name)
            print('+:', f2name)
        return fcompare(f1name, f2name)

    # read ndiff output from stdin, and print file1 (which=='1') or
    # file2 (which=='2') to stdout

    def restore(which):
        restored = difflib.restore(sys.stdin.readlines(), which)
        sys.stdout.writelines(restored)

    if __name__ == '__main__':
        main(sys.argv[1:])