89 lines
2.8 KiB
Dart
89 lines
2.8 KiB
Dart
class DictationTextAccumulator {
|
|
String _baseText = '';
|
|
String _recognizedText = '';
|
|
|
|
String get text =>
|
|
[_baseText, _recognizedText].where((part) => part.isNotEmpty).join(' ');
|
|
|
|
void begin(String existingText) {
|
|
_baseText = existingText.trimRight();
|
|
_recognizedText = '';
|
|
}
|
|
|
|
String addResult(String words) {
|
|
final nextText = words.trim().replaceAll(RegExp(r'\s+'), ' ');
|
|
if (nextText.isEmpty) return text;
|
|
|
|
_recognizedText = _mergeWithoutDeleting(_recognizedText, nextText);
|
|
return text;
|
|
}
|
|
|
|
String _mergeWithoutDeleting(String previousText, String nextText) {
|
|
if (previousText.isEmpty) return nextText;
|
|
|
|
final previousWords = _words(previousText);
|
|
final nextWords = _words(nextText);
|
|
|
|
if (_startsWith(nextWords, previousWords)) return nextText;
|
|
if (_startsWith(previousWords, nextWords)) return previousText;
|
|
|
|
final commonPrefixLength = _commonPrefixLength(previousWords, nextWords);
|
|
if (commonPrefixLength > 0) {
|
|
if (nextWords.length > previousWords.length) return nextText;
|
|
if (nextWords.length < previousWords.length) return previousText;
|
|
return nextText.length >= previousText.length ? nextText : previousText;
|
|
}
|
|
|
|
final overlapLength = _suffixPrefixOverlap(previousWords, nextWords);
|
|
if (overlapLength > 0) {
|
|
final originalNextWords = nextText.split(' ');
|
|
final remainingWords = originalNextWords.skip(overlapLength).join(' ');
|
|
return remainingWords.isEmpty
|
|
? previousText
|
|
: '$previousText $remainingWords';
|
|
}
|
|
|
|
return '$previousText $nextText';
|
|
}
|
|
|
|
List<String> _words(String value) {
|
|
return value
|
|
.toLowerCase()
|
|
.replaceAll(RegExp(r'[.,;:!?¿¡]'), '')
|
|
.split(RegExp(r'\s+'))
|
|
.where((word) => word.isNotEmpty)
|
|
.toList();
|
|
}
|
|
|
|
bool _startsWith(List<String> words, List<String> prefix) {
|
|
if (prefix.length > words.length) return false;
|
|
for (var index = 0; index < prefix.length; index++) {
|
|
if (words[index] != prefix[index]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int _commonPrefixLength(List<String> first, List<String> second) {
|
|
final limit = first.length < second.length ? first.length : second.length;
|
|
var commonWords = 0;
|
|
while (commonWords < limit && first[commonWords] == second[commonWords]) {
|
|
commonWords++;
|
|
}
|
|
return commonWords;
|
|
}
|
|
|
|
int _suffixPrefixOverlap(List<String> previous, List<String> next) {
|
|
final limit = previous.length < next.length ? previous.length : next.length;
|
|
for (var overlap = limit; overlap > 0; overlap--) {
|
|
var matches = true;
|
|
for (var index = 0; index < overlap; index++) {
|
|
if (previous[previous.length - overlap + index] != next[index]) {
|
|
matches = false;
|
|
break;
|
|
}
|
|
}
|
|
if (matches) return overlap;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|