so this is an interesting problem I am faced with. I have an array that I receive from a ASR server in a format like this [{start: 0, end: 0.4, word: "Hello"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name"}]
. The array is then mapped to an array of strings containing only the word e.g. ["Hello", "my", "name"]
finally that array is turned into a string using .join(" ")
resulting in a string like this "Hello my name"
.
The issue is trying to edit these values and maintain the original array's format. I am using a React Native TextInput to allow editing of the string value.
Let's say a user would like to change
"Hello my name"
to
"Hello my name is"
or
"Bellow my name"
In the first case the array would need to be adjusted to [{start: 0, end: 0.4, word: "Hello"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name is"}]
and in the second instance the array would have to be adjusted to [{start: 0, end: 0.4, word: "Bellow"}, {start: 0.4, end: 0.6, word: "my"}, {start: 0.6, end: 1, word: "name"}]
.
I am at a total loss as to how I should approach this. I have been at it for about two weeks now and still no idea. My latest attempt was to map through the original array comparing each item's word value to the edited string's word at the same index. If they matched, I would add them to the final array, if not I would check if the value in the edited string matches one of the changes that I got from the .difference()
function in Lodash.js. I might be explaining it poorly so have a look at the code.
const [value, setValue] = useState('');
const findChanges = () => {
let finalWords = [];
// Each of the elements in the currentWords array has three properties: start, end, word
let currentWords = data.words;
if (!Array.isArray(currentWords)) currentWords = JSON.parse(data.words);
// Extract only word strings from currentWords
let currentArr = currentWords.map(x => x.word);
let newArr = value.split(' ');
let currentChangeEndsAt = undefined;
let diff = difference(newArr, currentArr);
const addToFinal = (text: string, startIndex: number, endIndex: number) => {
if (startIndex === endIndex) {
return finalWords.push({ ...currentWords[startIndex], word: text });
}
let start = currentWords[startIndex].start;
let end = currentWords[endIndex].end;
return finalWords.push({ start, end, word: text });
};
currentArr.forEach((word, index) => {
// If index is smaller then we have already handled this word, skip
if (currentChangeEndsAt > index) {
return;
}
// If currentArr item at index matches newArr item at same index, add word to final
if (word === newArr[index]) {
return addToFinal(word, index, index);
}
// If currentArr item at index is one of the the differences
if (diff.indexOf(word) !== -1) {
// Determine recursively at which index the change ends
const changeEndsAt = (searchIndex): number => {
// If next word in currentArr matches the word in newArr at searchIndex return searchIndex
// Else add 1 to searchIndex and recursively call the func again
if (currentArr[index + 1] === newArr[searchIndex]) {
return searchIndex;
} else if (searchIndex === newArr.length - 1) {
return searchIndex;
} else {
return changeEndsAt(searchIndex + 1);
}
};
// Get substring of the change
const endsAt = changeEndsAt(index + 1);
const changeString = newArr.slice(index, endsAt).join(' ');
const endIndex =
endsAt > currentWords.length - 1 ? currentWords.length - 1 : endsAt;
return addToFinal(changeString, index, endIndex);
}
});
return finalWords;
};
As you can see it is quite a mess and you can probably tell that it won't work for a few reasons. One of the reasons being that if a word was added to the beginning of the string function would just break down. I have thought of maybe implementing an onChangeText handler and maybe setting the current cursor position of the TextInput in state using the onSelectionChange callback but I haven't been able to figure out how I would go from there. If anyone has any pointers on how I might approach this or even where to start that would help tremendously. I apologise for the longwinded question and vague title, I am open to suggestions on improving both. If you have a better idea for either please comment it below. Thanks in advance.