Diff de texto: Algoritmo y uso de herramientas en línea

Diff: el cálculo de diferencias omnipresente

Desde la gestión de versiones de Git hasta la revisión de código, desde cambios de configuración hasta la sincronización de datos — Diff es una operación fundamental en el desarrollo de software.

Escenario Tipo de Diff Herramienta
Cambios de código Diff por líneas Git
Comparación de configuración Diff por clave-valor Herramienta de comparación en línea
Datos JSON Diff estructurado json-diff
Documentos legales Diff semántico Herramienta especializada
Revisión de traducciones Diff por caracteres Comparación en línea

I. Principios del algoritmo Myers Diff

Idea central

El algoritmo Myers busca el script de edición más corto (SES) que convierte el texto fuente en el texto objetivo — la menor cantidad de operaciones de inserción/eliminación.

Fuente: ABCABBA
Objetivo: CBABAC

Script de edición:
- A    (eliminar A)
  B    (mantener B)
- C    (eliminar C)
  C    (mantener C → insertar C al principio)
  A    (mantener A)
  B    (mantener B)
- B    (eliminar B)
  A    (mantener A)
+ C    (insertar C)

Diagrama del algoritmo

      0   1   2   3   4   5   6   7
  ┌───┬───┬───┬───┬───┬───┬───┬───┐
0 │ → │ ↘ │   │   │   │   │   │   │  A
  ├───┼───┼───┼───┼───┼───┼───┼───┤
1 │ ↓ │   │ ↘ │   │ → │ ↘ │   │   │  B
  ├───┼───┼───┼───┼───┼───┼───┼───┤
2 │   │ ↓ │   │ ↘ │ ↓ │   │ ↘ │   │  C
  ├───┼───┼───┼───┼───┼───┼───┼───┤
3 │   │   │ ↓ │   │   │ ↓ │   │ ↘ │  A
  ├───┼───┼───┼───┼───┼───┼───┼───┤
4 │   │   │   │ ↓ │ ↘ │   │ ↓ │   │  B
  ├───┼───┼───┼───┼───┼───┼───┼───┤
5 │   │   │   │   │ ↓ │   │   │ ↓ │  B
  ├───┼───┼───┼───┼───┼───┼───┼───┤
6 │   │   │   │   │   │ ↓ │ ↘ │   │  A
  └───┴───┴───┴───┴───┴───┴───┴───┘
    C   B   A   B   A   C   B   A

→ = derecha (eliminar)  ↓ = abajo (insertar)  ↘ = diagonal (mantener)

Complejidad temporal

Caso Complejidad Descripción
Óptimo O(ND) N=longitud del texto, D=número de diferencias
Peor O((N+M)D) Textos completamente diferentes
Típico O(N+D²) Pocas diferencias

II. Uso de la herramienta de comparación de texto de Tools Ku

Pasos de operación

  1. Abre la Herramienta de comparación de texto
  2. Pega el texto original en el lado izquierdo
  3. Pega el texto modificado en el lado derecho
  4. Consulta los resultados de las diferencias:
    • Rojo: líneas eliminadas
    • Verde: líneas añadidas
    • Amarillo: líneas modificadas
  5. Soporta resaltado de diferencias por caracteres, preciso hasta cada cambio de carácter

Modos de comparación

Modo Granularidad Caso de uso
Por líneas Comparación por línea Cambios de código
Por palabras Comparación por palabra Revisiones de documentos
Por caracteres Comparación por carácter Corrección precisa

III. Técnicas especiales de JSON Diff

Uso de la herramienta JSON Diff

  1. Abre la Herramienta JSON Diff
  2. Pega dos datos JSON
  3. Consulta las diferencias estructuradas:
    • Claves añadidas/eliminadas/modificadas
    • Cambios de valores (incluyendo cambios de tipo)
    • Rutas anidadas

JSON Diff vs Diff de texto

// Original
{ "name": "张三", "age": 25, "tags": ["a", "b"] }

// Modificado
{ "name": "张三", "age": 26, "tags": ["a", "c"], "email": "z@test.com" }
Método de comparación Resultado
Diff de texto Muestra diferencias por línea, difícil de entender
JSON Diff age: 25→26, tags[1]: "b"→"c", +email: "z@test.com"

IV. Formato Diff unificado

Especificación del formato

--- a/config.json
+++ b/config.json
@@ -1,5 +1,6 @@
 {
   "name": "my-project",
-  "version": "1.0.0",
+  "version": "2.0.0",
   "description": "A tool",
-  "private": true
+  "private": true,
+  "license": "MIT"
 }
Símbolo Significado
--- Archivo original
+++ Archivo modificado
@@ -a,b +c,d @@ Posición de la diferencia (original desde línea a, b líneas; modificado desde línea c, d líneas)
- Línea eliminada
+ Línea añadida
(espacio) Línea de contexto

V. Generación y aplicación de parches

Generar parche

import * as Diff from 'diff';

const oldText = 'Hello World\nGoodbye World';
const newText = 'Hello World\nGoodbye Cruel World';

// Generar parche
const patch = Diff.createPatch('file.txt', oldText, newText, 'old', 'new');
console.log(patch);

Salida:

--- old/file.txt
+++ new/file.txt
@@ -1,2 +1,2 @@
 Hello World
-Goodbye World
+Goodbye Cruel World

Aplicar parche

// Aplicar hacia adelante
const result = Diff.applyPatch(oldText, patch);

// Aplicar en reversa (revertir)
const reversed = Diff.applyPatch(newText, Diff.reversePatch(patch));

Fusión de tres vías

const base = 'Texto original';
const branchA = 'Modificación de A';
const branchB = 'Modificación de B';

const merged = Diff.mergeDiff3(base, branchA, branchB);
// Fusión automática, marca conflictos con <<<<<<< / ======= / >>>>>>>

VI. Escenarios de aplicación práctica

Detección de cambios en archivos de configuración

const oldConfig = JSON.parse(fs.readFileSync('config.old.json', 'utf-8'));
const newConfig = JSON.parse(fs.readFileSync('config.new.json', 'utf-8'));

const diff = Diff.diffJson(oldConfig, newConfig);
diff.forEach(part => {
  if (part.added) console.log('Añadido:', JSON.stringify(part.value, null, 2));
  if (part.removed) console.log('Eliminado:', JSON.stringify(part.value, null, 2));
});

Revisión de archivos de traducción

// Comparar la consistencia de claves de traducción chino-inglés
const zhKeys = Object.keys(flatten(zhTranslation));
const enKeys = Object.keys(flatten(enTranslation));

const missingInEn = zhKeys.filter(k => !enKeys.includes(k));
const missingInZh = enKeys.filter(k => !zhKeys.includes(k));

Pruebas de regresión de respuestas de API

const expected = await fs.readFile('fixtures/expected.json', 'utf-8');
const actual = await fetch('/api/data').then(r => r.json());

const diff = Diff.diffJson(JSON.parse(expected), actual);
if (diff.some(d => d.added || d.removed)) {
  throw new Error('La respuesta de la API no coincide con la esperada');
}

VII. Optimización del rendimiento

Estrategia de optimización Efecto Aplicable a
Limitar líneas de contexto Reduce el tamaño de salida Archivos grandes
Preprocesamiento con hash Omite líneas idénticas Archivos muy grandes
Comparación por bloques Procesamiento en paralelo Textos muy largos
Nivel de línea antes que nivel de carácter Reduce la carga de cálculo Archivos de código
// Limitar líneas de contexto
const patch = Diff.createPatch('file', old, new, '', '', { context: 3 });
#Diff#文本对比#Patch#Myers#代码审查