Implemented function to compute minimal delta of two texts

This commit is contained in:
Benoy Bose 2025-03-28 17:26:49 +05:30
parent 6bbc953309
commit e3b6446c3b
2 changed files with 197 additions and 0 deletions

108
lib/utility.dart Normal file
View File

@ -0,0 +1,108 @@
class Word {
final int start;
final int end;
final String text;
Word({required this.start, required this.end, required this.text});
}
class WordDelta {
Word? old;
Word? modified;
WordDelta({this.old, this.modified});
}
class TextDelta {
final List<WordDelta> wordDeltas = [];
}
class Utility {
static List<Word> splitToWords(String text) {
List<Word> words = [];
String currentWord = "";
for (int i = 0; i < text.length; i++) {
if (text[i] == " " ||
text[i] == "\n" ||
text[i] == "\r" ||
text[i] == "\t") {
if (currentWord.isNotEmpty) {
words.add(
Word(start: i - currentWord.length, end: i, text: currentWord));
currentWord = "";
}
} else {
currentWord += text[i];
}
}
if (currentWord.isNotEmpty) {
words.add(Word(
start: text.length - currentWord.length,
end: text.length,
text: currentWord));
}
return words;
}
static List<TextDelta> compare(String oldText, String newText) {
var oldWords = splitToWords(oldText);
var newWords = splitToWords(newText);
int oldIndex = 0;
int newIndex = 0;
List<TextDelta> textDeltas = [];
while ((oldIndex < oldWords.length) && (newIndex < newWords.length)) {
var oldWord = oldWords[oldIndex];
var newWord = newWords[newIndex];
if (oldWord.text == newWord.text) {
oldIndex++;
newIndex++;
} else {
var delta = TextDelta();
delta.wordDeltas.add(WordDelta(old: oldWord, modified: newWord));
textDeltas.add(delta);
oldIndex++;
newIndex++;
if (oldIndex < oldWords.length && newIndex < newWords.length) {
var nextOldWord = oldWords[oldIndex];
var newSubIndex = newIndex;
var oldSubIndex = oldIndex;
while (newSubIndex < newWords.length &&
newWords[newSubIndex].text != nextOldWord.text) {
WordDelta wordDelta =
WordDelta(old: nextOldWord, modified: newWords[newSubIndex]);
delta.wordDeltas.add(wordDelta);
newSubIndex++;
oldSubIndex++;
}
if (newIndex != newSubIndex) {
newIndex = newSubIndex;
oldIndex = oldSubIndex;
}
}
}
}
if (newIndex < newWords.length) {
var delta = TextDelta();
while (newIndex < newWords.length) {
delta.wordDeltas.add(WordDelta(modified: newWords[newIndex]));
newIndex++;
}
textDeltas.add(delta);
}
if (oldIndex < oldWords.length) {
var delta = TextDelta();
while (oldIndex < oldWords.length) {
delta.wordDeltas.add(WordDelta(old: oldWords[oldIndex]));
oldIndex++;
}
textDeltas.add(delta);
}
return textDeltas;
}
}

89
test/utlity_test.dart Normal file
View File

@ -0,0 +1,89 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:fitlien_common/utility.dart';
void main() {
test('Test splitToWords function 1', () {
List<Word> words = Utility.splitToWords("This is a test sentence.");
expect(words.length, 5);
expect(words[0].text, "This");
expect(words[1].text, "is");
expect(words[2].text, "a");
expect(words[3].text, "test");
expect(words[4].text, "sentence.");
});
test('Test splitToWords function 2', () {
List<Word> words = Utility.splitToWords("This is a another sentence.");
expect(words.length, 5);
expect(words[0].text, "This");
expect(words[1].text, "is");
expect(words[2].text, "a");
expect(words[3].text, "another");
expect(words[4].text, "sentence.");
});
test('Comparison test 1', () {
var text1 = "ab bc cd";
var text2 = "ab cb cd";
var deltas = Utility.compare(text1, text2);
expect(deltas.length, 1);
expect(deltas[0].wordDeltas.length, 1);
expect(deltas[0].wordDeltas[0].old!.text, "bc");
expect(deltas[0].wordDeltas[0].modified!.text, "cb");
});
test('Comparison test 2', () {
var text1 = "ab bc cd";
var text2 = "ab cb dc";
var deltas = Utility.compare(text1, text2);
expect(deltas.length, 1);
expect(deltas[0].wordDeltas.length, 2);
expect(deltas[0].wordDeltas[0].old!.text, "bc");
expect(deltas[0].wordDeltas[0].modified!.text, "cb");
expect(deltas[0].wordDeltas[1].old!.text, "cd");
expect(deltas[0].wordDeltas[1].modified!.text, "dc");
});
test('Comparison test 3', () {
var text1 = "ab bc cd fe";
var text2 = "ab cb cd ef";
var deltas = Utility.compare(text1, text2);
expect(deltas.length, 2);
expect(deltas[0].wordDeltas.length, 1);
expect(deltas[0].wordDeltas[0].old!.text, "bc");
expect(deltas[0].wordDeltas[0].modified!.text, "cb");
expect(deltas[1].wordDeltas.length, 1);
expect(deltas[1].wordDeltas[0].old!.text, "fe");
expect(deltas[1].wordDeltas[0].modified!.text, "ef");
});
test('Comparison test 4', () {
var text1 = "ab bc";
var text2 = "ab cb cd ef";
var deltas = Utility.compare(text1, text2);
expect(deltas.length, 2);
expect(deltas[0].wordDeltas.length, 1);
expect(deltas[0].wordDeltas[0].old!.text, "bc");
expect(deltas[0].wordDeltas[0].modified!.text, "cb");
expect(deltas[1].wordDeltas.length, 2);
expect(deltas[1].wordDeltas[0].old, null);
expect(deltas[1].wordDeltas[0].modified!.text, "cd");
expect(deltas[1].wordDeltas[1].old, null);
expect(deltas[1].wordDeltas[1].modified!.text, "ef");
});
test('Comparison test 5', () {
var text1 = "ab bc cd ef";
var text2 = "ab cb";
var deltas = Utility.compare(text1, text2);
expect(deltas.length, 2);
expect(deltas[0].wordDeltas.length, 1);
expect(deltas[0].wordDeltas[0].old!.text, "bc");
expect(deltas[0].wordDeltas[0].modified!.text, "cb");
expect(deltas[1].wordDeltas.length, 2);
expect(deltas[1].wordDeltas[0].old!.text, "cd");
expect(deltas[1].wordDeltas[0].modified, null);
expect(deltas[1].wordDeltas[1].old!.text, "ef");
expect(deltas[1].wordDeltas[1].modified, null);
});
}