You can tokenize the whole output and then process the tokens one by one:
// Note the outer parentheses! These form a capturing group,
// whose match's content will be pushed back to the splitted array at odd indices.
const tokenizer = new RegExp(`(${words.join('|')})`, 'i');
input.addEventListener('input', function() {
const value = this.value;
const tokens = value.split(tokenizer);
let joined = '';
for (const [index, token] of tokens.entries()) {
const isRegisteredWord = index % 2 === 1;
if (isRegisteredWord) {
const { abbreviated, tooltip } = wordToAbbreviation[token.toLowerCase()];
joined += `<abbr title="${tooltip}">${abbreviated}</abbr>`;
} else {
joined += token;
}
}
output.innerHTML = joined;
});
To avoid unnecessary iteration, changing the data structure to something like this is essential:
const dictionary = {
M: {
'mobile telephone number': {
abbreviated: 'M/TEL',
tooltip: 'Mobile telephone number'
}
},
T: {
telephone: {
abbreviated: 'TEL',
tooltip: 'Telephone'
}
}
};
// Flattening is required, however.
const wordToAbbreviation = Object.assign(
Object.create(null),
...Object.values(dictionary)
);
...or you can afford removing the grouping altogether so that the second step is unnecessary:
const dictionary = {
'mobile telephone number': {
abbreviated: 'M/TEL',
tooltip: 'Mobile telephone number'
}
telephone: {
abbreviated: 'TEL',
tooltip: 'Telephone'
}
};
Try it:
const dictionary = {
M: {
'mobile telephone number': {
abbreviated: 'M/TEL',
tooltip: 'Mobile telephone number'
}
},
T: {
telephone: {
abbreviated: 'TEL',
tooltip: 'Telephone'
}
}
};
const wordToAbbreviation = Object.assign(
Object.create(null),
...Object.values(dictionary)
);
const input = document.getElementById('input');
const output = document.getElementById('output');
const words = Object.keys(wordToAbbreviation);
const tokenizer = new RegExp(`(${words.join('|')})`, 'i');
input.addEventListener('input', function() {
const value = this.value;
const tokens = value.split(tokenizer);
let joined = '';
for (const [index, token] of tokens.entries()) {
const isRegisteredWord = index % 2 === 1;
if (isRegisteredWord) {
const { abbreviated, tooltip } = wordToAbbreviation[token.toLowerCase()];
joined += `<abbr title="${tooltip}">${abbreviated}</abbr>`;
} else {
joined += token;
}
}
output.innerHTML = joined;
});
input.dispatchEvent(new InputEvent('input'));
<textarea id="input" placeholder="Enter message">mobile TelePhone nuMbeR</textarea>
<p id="output"></p>