JS регулярные выражение как отформатировать правильно html?
Сегодня целый день изучаю регулярные выражение, так и не смог решить проблему. Попытаюсь объяснить на примерах.
Есть на входе:
<div class="dialog__row_1">{FFFFFF}Склад:{33CCCC}%d {FFFFFF}из {33CCCC}%d</div>
<div class="dialog__row_2">Продуктов:%s</div>
<div class="dialog__row_2">{FFFFFF}Введите сколько желаете заказать:</div>
- Нужно, чтобы регулярное выражение, заменила {FFFFFF} на
<span style="color:#FFFFFF">
а закрывающий
</span>
выставить перед следующим {33CCCC}, и так пройтись по всем цветам.
- Теперь самое сложное, у dialog__row_1 последний цвет {33CCCC} и должно получится
<span style="color:#33CCCC">%d</span>
Но у dialog__row_2 не указал цвет в {}, поэтому надо продублировать последний цвет из dialog__row_1
Как должно быть в финале:
<div class="dialog__row_1">
<span style="color:#FFFFFF">Склад: </span>
<span style="color:#33CCCC">%d </span>
<span style="color:#FFFFFF">из </span>
<span style="color:#33CCCC">%d</span> // Пункт 1
</div>
<div class="dialog__row_2">
<span style="color:#33CCCC">Продуктов: %s</span> // Цвет взят из пункт 1
</div>
<div class="dialog__row_2">
<span style="color:#FFFFFF">Введите сколько желаете заказать:</span>
</div>
Ответы (2 шт):
Если вы делаете эту замену на стороне клиента, тогда стоит работать только с текстом элементов. И придётся использовать функцию замены, сохраняя где-то текущие состояния для наличия предыдущей замены и для последнего цвета.
function colorize(match) {
const color = match.slice(1, -1);
const replacement =
`${colorize.isTextChanged ? '</span>' : ''}<span style="color:#${color}">`;
colorize.lastColor = color;
colorize.isTextChanged = true;
return replacement;
}
colorize.lastColor = null;
colorize.isTextChanged = false;
const divs = document.querySelectorAll('div[class^="dialog__row_"]');
for (const div of divs) {
const text = div.textContent;
if (!/\{[0-9A-F]{6}\}/u.test(text)) {
if (colorize.lastColor) {
div.innerHTML = `<span style="color:#${colorize.lastColor}">${text}</span>`;
}
} else {
div.innerHTML = `${text.replace(/\{[0-9A-F]{6}\}/gu, colorize)}</span>`;
}
colorize.isTextChanged = false;
}
console.log(document.querySelector('#main').innerHTML);
<div id="main">
<div class="dialog__row_1">{FFFFFF}Склад:{33CCCC}%d {FFFFFF}из {33CCCC}%d</div>
<div class="dialog__row_2">Продуктов:%s</div>
<div class="dialog__row_2">{FFFFFF}Введите сколько желаете заказать:</div>
</div>
Если заменяете на стороне сервера, стоит использовать сначала что-нибудь для парсинга HTML и потом применить тот же подход.
Прежде разбиваем строку:
// Из этого '{FFFFFF}Склад:{33CCCC}%d {FFFFFF}из {33CCCC}%d'
// получаем такой массив
['{FFFFFF}Склад:', '{33CCCC}%d ','{FFFFFF}из ', '{33CCCC}%d']
// ... а из этого 'Продуктов:%s', останется как есть
['Продуктов:%s']
Далее легко извлекается цвет и оборачивается span-ном. Сохраняем последний извлеченный цвет. Какой либо цвет стоит установить по умолчанию, на случай первой строки без {ffffff}.
const reSplit = /(?=\{[0-9A-F]{6}\})/ig
const reColor = /\{[0-9A-F]{6}\}/i
let lastColor = 'FFFFFF' // default Color
const wrap = (str) => `<span style="color:#${lastColor}">${str}</span>`
function colorize(str) {
return str.split(reSplit)
.map((str) => {
// Если это цвет
const match = str.match(reColor)
if (match) {
// Извлекаем цвет ... сохраняем ... и удаляем его из строки
lastColor = match[0].replace(/[\{\}]/g, '')
return wrap(str.replace(reColor, ''))
}
// Иначе унаследовать
return wrap(str)
})
.join('')
}
const rows = document.querySelectorAll('div[class^="dialog__row_"]')
for (let element of rows) {
const text = colorize(element.textContent)
console.log(text)
element.innerHTML = text
}
body {
background-color: #5e5e5e;
}
<div class="dialog__row_1">{FFFFFF}Склад:{33CCCC}%d {FFFFFF}из {33CCCC}%d</div>
<div class="dialog__row_2">Продуктов:%s</div>
<div class="dialog__row_2">{FFFFFF}Введите сколько желаете заказать:</div>