Finden des Unterschieds zwischen zwei Zeichenfolgen in Java

1. Übersicht

Dieses kurze Tutorial zeigt, wie Sie mit Java den Unterschied zwischen zwei Zeichenfolgen ermitteln .

In diesem Tutorial werden wir zwei vorhandene Java-Bibliotheken verwenden und ihre Ansätze für dieses Problem vergleichen.

2. Das Problem

Betrachten wir die folgende Anforderung: Wir möchten den Unterschied zwischen den Zeichenfolgen " ABCDELMN" und "ABCFGLMN" ermitteln.

Je nachdem, welches Format die Ausgabe haben soll, und ohne die Möglichkeit, unseren benutzerdefinierten Code zu schreiben, haben wir zwei Hauptoptionen gefunden.

Die erste ist eine von Google geschriebene Bibliothek namens Diff-Match-Patch. Wie sie behaupten, bietet die Bibliothek robuste Algorithmen zum Synchronisieren von einfachem Text .

Die andere Option ist die StringUtils- Klasse von Apache Commons Lang.

Lassen Sie uns die Unterschiede zwischen diesen beiden untersuchen.

3. Diff-Match-Patch

Für den Zweck dieses Artikels verwenden wir eine Abzweigung der ursprünglichen Google-Bibliothek, da die Artefakte für die ursprüngliche nicht in Maven Central veröffentlicht werden. Außerdem unterscheiden sich einige Klassennamen von der ursprünglichen Codebasis und entsprechen eher den Java-Standards.

Zuerst müssen wir die Abhängigkeit in unsere Datei pom.xml aufnehmen :

 org.bitbucket.cowwoc diff-match-patch 1.2 

Betrachten wir dann diesen Code:

String text1 = "ABCDELMN"; String text2 = "ABCFGLMN"; DiffMatchPatch dmp = new DiffMatchPatch(); LinkedList diff = dmp.diffMain(text1, text2, false);

Wenn wir den obigen Code ausführen, der den Unterschied zwischen text1 und text2 erzeugt, erzeugt das Drucken der Variablen diff diese Ausgabe:

[Diff(EQUAL,"ABC"), Diff(DELETE,"DE"), Diff(INSERT,"FG"), Diff(EQUAL,"LMN")]

Tatsächlich ist die Ausgabe eine Liste von Diff- Objekten , die jeweils durch einen Operationstyp ( INSERT , DELETE oder EQUAL ) und den der Operation zugeordneten Textteil gebildet werden .

Wenn Sie den Unterschied zwischen text2 und text1 ausführen, erhalten Sie folgendes Ergebnis:

[Diff(EQUAL,"ABC"), Diff(DELETE,"FG"), Diff(INSERT,"DE"), Diff(EQUAL,"LMN")]

4. StringUtils

Die Klasse von Apache Commons hat einen einfacheren Ansatz .

Zuerst fügen wir die Apache Commons Lang-Abhängigkeit zu unserer pom.xml- Datei hinzu:

 org.apache.commons commons-lang3 3.9 

Um den Unterschied zwischen zwei Texten mit Apache Commons zu ermitteln, würden wir StringUtils # Difference aufrufen :

StringUtils.difference(text1, text2)

Die erzeugte Ausgabe ist eine einfache Zeichenfolge :

FGLMN

Wenn Sie den Unterschied zwischen text2 und text1 ausführen, wird Folgendes zurückgegeben:

DELMN

Dieser einfache Ansatz kann mit verbessert werden StringUtils.indexOfDifference () , die die Rückkehr wird Index , an dem die beiden Strings zu unterscheiden beginnen (in unserem Fall das vierte Zeichen des Strings). Dieser Index kann verwendet werden, um eine Teilzeichenfolge der ursprünglichen Zeichenfolge abzurufen und zu zeigen, was zwischen den beiden Eingaben gemeinsam ist und was unterschiedlich ist.

5. Leistung

Für unsere Benchmarks generieren wir eine Liste mit 10.000 Zeichenfolgen mit einem festen Anteil von 10 Zeichen , gefolgt von 20 zufälligen alphabetischen Zeichen .

Wir durchlaufen dann die Liste und führen einen Unterschied zwischen dem n-ten Element und dem n + 1- ten Element der Liste durch:

@Benchmark public int diffMatchPatch() { for (int i = 0; i < inputs.size() - 1; i++) { diffMatchPatch.diffMain(inputs.get(i), inputs.get(i + 1), false); } return inputs.size(); }
@Benchmark public int stringUtils() { for (int i = 0; i < inputs.size() - 1; i++) { StringUtils.difference(inputs.get(i), inputs.get(i + 1)); } return inputs.size(); }

Lassen Sie uns abschließend die Benchmarks ausführen und die beiden Bibliotheken vergleichen:

Benchmark Mode Cnt Score Error Units StringDiffBenchmarkUnitTest.diffMatchPatch avgt 50 130.559 ± 1.501 ms/op StringDiffBenchmarkUnitTest.stringUtils avgt 50 0.211 ± 0.003 ms/op

6. Fazit

In Bezug auf die reine Ausführungsgeschwindigkeit ist StringUtils deutlich leistungsfähiger , obwohl nur der Teilstring zurückgegeben wird, von dem sich die beiden Strings zu unterscheiden beginnen.

Gleichzeitig liefert Diff-Match-Patch ein gründlicheres Vergleichsergebnis auf Kosten der Leistung.

Die Implementierung dieser Beispiele und Snippets ist über GitHub verfügbar.