I am facing an issue related to wrapping the flag words with HTML. The flag words response is coming from a third-party service as an array of objects. The paragraph text is something like this:
Hi, my nme is John, and I am from uas.\nthis sentce dones mke sense.\nHi, my nme is John, and I am from uas.
and the flag words response is this:
[
{ offset: 7, token: 'nme', type: 'UnknownToken' },
{ offset: 52, token: 'dones', type: 'UnknownToken' },
{ offset: 58, token: 'mke', type: 'UnknownToken' }
]
I want to wrap the flag tokens with the following HTML tag.
<span class="underline">nme</span>
The response already has the offset
and token
keys, but my logic is not correctly working with these keys, I am replacing the string on the offset index, but the output is not correct.
My logic:
function replaceAt(str, index, replacement) {
return (
str.substring(0, index) +
replacement +
str.substring(index + replacement.length)
);
}
let input = `Hi, my nme is John, and I am from uas.\nthis sentce dones mke sense\nHi, my nme is John, and I am from uas.`;
const flagTokens = [
{ offset: 7, token: "nme", type: "UnknownToken" },
{ offset: 52, token: "dones", type: "UnknownToken" },
{ offset: 58, token: "mke", type: "UnknownToken" },
];
flagTokens.forEach((item) => {
input = replaceAt(
input,
item.offset,
`<span class="underline">${item.token}</span>`
);
});
console.log("Output:", input);
Output:
Hi, my <span class="underline">nme</span>his sentce <span <span class="underline">mke</span>
How can I solve this issue?
6
Answers
Perhaps this solution is what you are looking for
Output
The error in your logic
A better solution would be
Use
replace()
insteadWell, there are two issues with your code.
The first one is that after you replace the first token, your string has gotten longer, and now the offsets of the rest of the tokens are wrong since they have moved forward. A solution to this is to apply the replacements from the last to the first (since they are ordered in offset order)
The second issue is that your replacement method
replaceAt
after inserting the replacement text it continues to addstr.substring(index + replacement.length)
. But that is wrong. You only need to add thetoken
length and not thereplacement
length. So you should pass that as well in the function.I think
.replace()
is a good and elegant solution for the general case where you want to "underline" all or just the first occurrences for a given token, but it struggles if you want to underline those at particular indexes like you have in yourflagToken
array, as you may not want to underline all or just the first occurance of a given token, but rather a particular one if they appear multiple times.One option could be to loop through your string. If the index your on does not appear in your
flagTokens
array then you can add the current character to a resulting string (res
). If the index does appear in your array as anoffset
, then you can add your token wrapped in your<span>
to the resulting stringres
, and then add the length of thetoken
to the current index (skipping the rest of the token) to then process the remaining indexes of the string. By keeping the originalinput
string untouched, you don’t need to worry about adjusting your offset based on the characters added by the<span>...</span>
, as those are added tores
, eg:Easiest solution is to start at the end and work your way forward so you do not have to worry about the characters you are adding into the string.
Other option is keeping track what you add and adding that to the offset