diff --git a/lib/utility.dart b/lib/utility.dart new file mode 100644 index 0000000..bd775bc --- /dev/null +++ b/lib/utility.dart @@ -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 wordDeltas = []; +} + +class Utility { + static List splitToWords(String text) { + List 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 compare(String oldText, String newText) { + var oldWords = splitToWords(oldText); + var newWords = splitToWords(newText); + + int oldIndex = 0; + int newIndex = 0; + + List 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; + } +} diff --git a/test/utlity_test.dart b/test/utlity_test.dart new file mode 100644 index 0000000..9d12f88 --- /dev/null +++ b/test/utlity_test.dart @@ -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 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 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); + }); +}