Я разрабатываю функцию в своем приложении, которая выполняет поиск по тексту и сокращает слова/фразы, пока пользователь вводит текст.
let dictionary = {
"M": {
"Mobile telephone number": "M/TEL"
},
"T": {
"Telephone": "TEL"
}
};
function abbreviateText() {
const input = document.getElementById("input").value;
let output = input;
for (const groupKey in dictionary) {
const group = dictionary[groupKey];
for (const key in group) {
const regex = new RegExp(`\\b${key}\\b`, "gi");
const replacement = `<span class = "tooltip" data-tooltip = "${key}">${group[key]}</span>`;
output = output.replace(regex, replacement);
}
}
document.getElementById("output").innerHTML = output;
}
<textarea id = "input" placeholder = "Enter message" rows = "7" oninput = "abbreviateText()"></textarea>
<p id = "output"></p>
При вводе mobile telephone number
должно выводиться M/TEL
вместо TEL number">M/TEL
.
Исходный вывод должен быть <span class = "tooltip" data-tooltip = "Mobile telephone number">M/TEL"</span>
. Обратите внимание, что нет тега span
, охватывающего TEL
.
У меня есть другие случаи этого, поэтому решение должно быть общим.
🤔 А знаете ли вы, что...
JavaScript поддерживает работу с куки и хранилищем веб-браузера для сохранения данных на клиентской стороне.
Если вы уверены, что ваш первоначальный ввод не содержит HTML, вы можете использовать двухэтапную замену.
Также вам нужно сначала убедиться, что у вас есть «более длинные» замены.
let dictionary = {
"M": {
"Mobile telephone number": "M/TEL"
},
"T": {
"Telephone": "TEL"
}
};
const replacements = Object
.values(dictionary)
.flatMap(obj => Object.entries(obj))
.sort((a, b) => a[0] < b[0])
function abbreviateText() {
const input = document.getElementById("input").value;
let output = input;
const found = []
for (const [key, value] of replacements) {
const regex = new RegExp(`\\b${key}\\b`, "gi");
if (regex.test(output)) {
output = output.replace(regex, `__replacement:${found.length}`);
found.push([found.length, `<span class = "tooltip" data-tooltip = "${key}">${value}</span>`])
}
}
for (const [index, replacement] of found) {
output = output.replace(new RegExp(`__replacement:${index}`, 'gi'), replacement)
}
document.getElementById("output").innerHTML = output;
}
<textarea id = "input" placeholder = "Enter message" rows = "7" oninput = "abbreviateText()"></textarea>
<p id = "output"></p>
Вы можете токенизировать весь вывод, а затем обрабатывать токены один за другим:
// 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;
});
Чтобы избежать ненужных итераций, важно изменить структуру данных на что-то вроде этого:
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)
);
... или вы можете позволить себе полностью удалить группировку, так что второй шаг не нужен:
const dictionary = {
'mobile telephone number': {
abbreviated: 'M/TEL',
tooltip: 'Mobile telephone number'
}
telephone: {
abbreviated: 'TEL',
tooltip: 'Telephone'
}
};
Попробуй это:
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>