Implemented function to compute minimal delta of two texts
This commit is contained in:
parent
6bbc953309
commit
e3b6446c3b
108
lib/utility.dart
Normal file
108
lib/utility.dart
Normal 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
89
test/utlity_test.dart
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user