# Diff-Checker & Smart-Formatter – Text, Code, JSON und Markdown lokal vergleichen

> **Autor:** Lukas Kopischke (Lead Software-Engineer, Düsseldorf)
> **Kanonische URL:** https://lukiluki.me/garden/diff-checker
> **Markdown-Endpunkt:** https://lukiluki.me/garden/diff-checker.md
> **Kategorie:** Workflows & Testing | **Tags:** Myers-Diff, JSON, Markdown, Syntax-Highlighting, Offline-PWA
> **Veröffentlicht:** 2026-10-26 | **Aktualisiert:** 2026-10-26
> **Zusammenfassung:** Offline-fähiger Diff-Checker im Browser: Texte, Code, JSON und Markdown mit automatischer Formatierung, Syntax-Highlighting und Live-Vorschau vergleichen.

---
Du bekommst einen überarbeiteten Vertragsentwurf, eine von KI umformulierte Markdown-Dokumentation oder zwei einzeilige JSON-Antworten aus einer Schnittstelle und willst in Sekunden wissen, welches Detail sich tatsächlich verändert hat. Klassische Online-Vergleichsseiten schicken solche sensiblen Inhalte jedoch häufig an fremde Server oder markieren bei umsortiertem JSON den gesamten Block pauschal als geändert.

Ein lokaler Browser-Diff zerlegt beide Eingaben im Arbeitsspeicher über den Myers-Algorithmus in Zeilen- und Wort-Token und berechnet die kleinste Folge aus Einfügungen und Löschungen. Bringt ein vorgeschalteter Formatter unstrukturierte Eingaben zuerst in eine einheitliche Form – etwa durch alphabetisch sortierte JSON-Schlüssel –, bleiben nur noch echte Inhaltsänderungen übrig. Bei dateiübergreifenden Code-Umbauten oder mehrstelligen Megabyte-Logs stößt ein Browser-Vergleich dagegen an seine Grenzen.

> **Merksatz:**
> Gute Text- und Codevergleiche trennen Form von Inhalt: Erst die Normalisierung von Zeilenumbrüchen, Einrückungen und Schlüsselreihenfolgen macht aus rohem Zeichenrauschen eine verlässliche Änderungsprüfung.

## Warum reine Zeilenvergleiche täuschen und wie der Myers-Algorithmus arbeitet

Hinter fast jedem modernen Diff-Werkzeug – einschließlich `git diff` – steckt der 1986 von Eugene W. Myers veröffentlichte Algorithmus für das Kürzestes Edit-Skript (SES) (Minimale Folge von Lösch- und Einfügeoperationen, die Text A in Text B überführt; das Gegenstück dazu ist die längste gemeinsame Teilfolge (Longest Common Subsequence).). Seine Laufzeit liegt bei `O((N + M) · D)`, wobei `N` und `M` die Anzahl der Zeilen oder Wörter beider Texte beschreiben und `D` für die Anzahl der tatsächlichen Unterschiede steht. Sind sich zwei Dokumente ähnlich (`D` ist klein), läuft der Vergleich im Browser selbst bei tausenden Zeilen in wenigen Millisekunden durch.

In der Praxis scheitert ein Vergleich selten am Algorithmus, sondern an **Schein-Unterschieden** in der Eingabe:

1. **Einzeiliges oder umsortiertes JSON:** Laut RFC 8259 sind JSON-Objekte ungeordnete Schlüssel-Wert-Sammlungen (`{"a":1,"b":2}` bedeutet fachlich exakt dasselbe wie `{"b":2,"a":1}`). Ein reiner Textvergleich meldet hier fälschlich 100 Prozent Abweichung, solange die Schlüssel vorab nicht in eine Kanonische Normalform (Eindeutige Standarddarstellung einer Datenstruktur – etwa feste Einrückung und alphabetisch sortierte Objektschlüssel –, sodass semantisch gleiche Daten identischen Text ergeben.) gebracht werden.
2. **Lange Fließtext-Absätze:** In Verträgen, E-Mails oder Dokumentationen ist ein ganzer Absatz oft eine einzige lange Zeile ohne manuellen Zeilenumbruch. Markiert ein Werkzeug nur die komplette Zeile rot und grün, übersieht das Auge leicht ein einzelnes eingefügtes Wort wie *„nicht“* oder eine geänderte Kündigungsfrist. Erst ein zweistufiger Durchlauf – zuerst Zeilen-Diff, innerhalb geänderter Zeilenpaare anschließend Wort-Diff – hebt die exakte Stelle hervor.
3. **Gemischte Zeilenenden (`CRLF` vs. `LF`):** Kopierst du einen Text aus einem Windows-Editor und den zweiten aus einer Linux-Konsole oder einem Chatfenster, weicht jedes Zeilenende unsichtbar um das Steuerzeichen `\r` ab.

```typescript
import { diffLines } from "diff";

// Rekursive kanonische Sortierung verhindert Fehlalarme bei JSON-Vergleichen
export function canonicalizeJson(rawJson: string): string {
  const sortDeep = (val: unknown): unknown => {
    if (Array.isArray(val)) {
      // Array-Reihenfolge bleibt bewusst erhalten, da sie fachlich relevant sein kann!
      return val.map(sortDeep);
    }
    if (val !== null && typeof val === "object") {
      return Object.fromEntries(
        Object.entries(val as Record<string, unknown>)
          .sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
          .map(([key, nested]) => [key, sortDeep(nested)])
      );
    }
    return val;
  };

  const parsed: unknown = JSON.parse(rawJson);
  return JSON.stringify(sortDeep(parsed), null, 2);
}

export function diffJsonPayloads(beforeRaw: string, afterRaw: string) {
  const normalizedBefore = canonicalizeJson(beforeRaw);
  const normalizedAfter = canonicalizeJson(afterRaw);
  return diffLines(normalizedBefore, normalizedAfter);
}
```

Beachte im Code ein wichtiges Detail: Objektschlüssel dürfen alphabetisch sortiert werden, **Arrays (`[...]`) dagegen nicht automatisch**, weil `[10, 20]` und `[20, 10]` in vielen Schnittstellen eine fachlich bedeutsame Reihenfolge (z. B. Prioritäten oder Zeitreihen) abbilden.

## Welches Vergleichsverfahren passt zu welchem Dokumenttyp?

| Dokumenttyp | Bestes Vergleichsverfahren | Warum es hilft | Wann ein anderes Werkzeug besser ist |
| :--- | :--- | :--- | :--- |
| **Verträge, E-Mails & KI-Textüberarbeitungen** | Zeilen- + Wort-Diff (Unified oder Split) | Zeigt ausgetauschte Zahlen, Fristen und Füllwörter mitten im Satz | Bei Layout-Prüfungen in formatierten Word- oder PDF-Dokumenten mit Fußnoten |
| **API-Antworten & Konfigurations-JSON** | Kanonische Formatierung + Zeilen-Diff | Blendet Minifizierung und zufällige Key-Reihenfolgen aus | Bei riesigen JSON-Dumps über ~5–10 MB (`jq --sort-keys` im Terminal ist dort stabiler) |
| **Markdown-Dokumentation & Tabellen** | Quelltext-Diff + gerenderte Vorschau | Erkennt gleichzeitig Tippfehler im Text und zerschossene Tabellen-Spalten | Bei komplexen MDX-Dateien mit eigenen React-Komponenten (siehe [MDX-Leitfaden](/garden/mdx)) |
| **Mehrteilige Quellcode-Refactorings** | Lokales `git diff --color-moved` / IDE | Verfolgt verschobene Funktionen und umbenannte Dateien über Ordner hinweg | Einzeldatei-Vergleich im Browser kennt keinen Projektkontext (siehe [Git Workflows](/garden/git-workflows)) |

  #### Empfohlen (Do): Verlässliche Prüfroutine
* Vor dem Vergleich von JSON- oder Code-Snippets immer **Smart Formatieren** ausführen, um Formatierungsrauschen zu entfernen
    * Bei Verträgen, AGB oder sensiblen Kundendaten ausschließlich **lokal im Browser arbeitende Werkzeuge** ohne Server-Übertragung einsetzen
    * Bei Markdown-Tabellen und Checklisten kurz in die **gerenderte Ansicht** wechseln, um vergessene Pipe-Zeichen (`|`) sofort zu sehen
  #### Vermeiden (Don't): Häufige Fehlschlüsse
* „Leerzeichen ignorieren“ nicht blind bei **Python** oder **YAML** aktivieren – dort verändert die Einrückung die Programmlogik!
    * Arrays in JSON nicht unbesehen alphabetisch sortieren, wenn die Reihenfolge der Einträge fachliches Gewicht hat
    * Mehrstellige Megabyte-Serverlogs nicht im Browser-DOM rendern, sondern per Kommandozeile (`diff -u` oder `git diff --no-index`) filtern

> **Wann eine .patch-Datei im Alltag Zeit spart**
> Über den Button *Als .patch kopieren* erzeugst du ein standardisiertes Unified-Diff-Format. Entwickler können diese Textdatei direkt mit `git apply aenderungen.patch` einspielen, und Sprachmodelle verstehen ein kurzes Patch-Snippet oft präziser und tokensparender als zwei komplett kopierte Quelldateien.

## Prüfpunkte beim Prüfen von Code, JSON und Verträgen

- [ ] **Datenschutz vor dem Einfügen klären:** Enthält der Text personenbezogene Daten, API-Schlüssel oder Vertragsentwürfe, darf kein Netzwerk-Request stattfinden (prüfbar im Browser-Netzwerk-Tab oder im Flugmodus der installierten PWA).
- [ ] **Einrückungssensitive Formate beachten:** Prüfst du YAML, Python oder Markdown-Codeblöcke, lasse die Option *Leerzeichen ignorieren* ausgeschaltet.
- [ ] **Zahlen und Negationen einzeln gegenlesen:** Achte in den farbig hinterlegten Wort-Markierungen gezielt auf kleine Wörter (*„nicht“*, *„höchstens“*, *„exklusive“*) sowie geänderte Einheiten (*Tage* vs. *Werktage*, *ms* vs. *s*).

## Quellen und nächste Schritte

* **Eugene W. Myers (1986)** – *An O(ND) Difference Algorithm and Its Variations (Algorithmica, Vol. 1, S. 251–266)*: [xmailserver.org/diff2.pdf](http://www.xmailserver.org/diff2.pdf)
* **IETF RFC 8259** – *The JavaScript Object Notation (JSON) Data Interchange Format (Objekt-Ungeordnetheit in Sektion 4)*: [datatracker.ietf.org/doc/html/rfc8259](https://datatracker.ietf.org/doc/html/rfc8259)
* **GitHub Flavored Markdown Spec (GFM)** – *Tabellen, Task-Listen und Fenced Code Blocks*: [github.github.com/gfm](https://github.github.com/gfm/)
* **jsdiff (Referenzimplementierung für Zeilen- & Wort-Diffs in JavaScript)** – [github.com/kpdecker/jsdiff](https://github.com/kpdecker/jsdiff)
* **Weiterführend im Digital Garden:** Lies [Git Workflows](/garden/git-workflows) für saubere Commit- und Review-Strategien in Teams oder [MDX – Markdown trifft React-Komponenten](/garden/mdx), wenn aus statischem Markdown interaktive Oberflächen werden sollen.

---
*Quelle: [Lukas Kopischke – Digital Garden](https://lukiluki.me/garden/diff-checker) | Vollständiger Index: [llms.txt](https://lukiluki.me/llms.txt)*
