Как выявить инлайн-стили в коде и заменить их на соответствующие HTML-теги?

Здравствуйте! 

У меня возникла необходимость адаптировать текст, который копируется из MS Word в кастомный WYSIWYG редактор. При копировании, с текстом приходят и теги со стилями. Задача состоит в том, чтобы выявлять жирный и курсивный текст, а также учитывать размер шрифта, чтобы заменять соответствующие теги на нужные.

Например, приходит следующий код:

<pre><code class="javascript">&lt;p dir="ltr" style="line-height:1.2;margin-top:0pt;margin-bottom:0pt;"&gt;
&lt;span style="font-size:13.999999999999998pt;font-family:Calibri,sans-serif;color:#000000;background-color:#ffffff;font-weight:400;font-style:italic;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"&gt;
   Тут текст
&lt;/span&gt;
&lt;/p&gt;</code></pre> 

В этом случае нужно определить, что значение `font-style` равно `italic`, и заменить тег `span` на `strong`, удалив все инлайновые стили, чтобы получить следующий результат:

<pre><code class="javascript">&lt;p&gt;
   &lt;strong&gt;Тут текст&lt;/strong&gt;
&lt;/p&gt;</code></pre>

Вот еще один пример:

<pre><code class="javascript">&lt;p dir="ltr" style="line-height:1.2;margin-top:0pt;margin-bottom:0pt;"&gt;
&lt;span style="font-size:18pt;font-family:Calibri,sans-serif;color:#000000;background-color:#ffffff;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"&gt;
   Тут текст
&lt;/span&gt;
&lt;/p&gt;</code></pre>

В этом случае нужно выявить, что `font-size` равен `18`, и заменить `span` на `h2`, в результате чего мы получим:

<pre><code class="javascript">&lt;p&gt;
   &lt;h2&gt;Тут текст&lt;/h2&gt;
&lt;/p&gt;</code></pre> 

Как правильно реализовать такую логику преобразования?
  • 28 ноября 2024 г. 10:43
Ответы на вопрос 2
Для реализации логики преобразования инлайн-стилей в соответствующие HTML-теги, вы можете использовать JavaScript или Python с библиотеками для работы с HTML. В этом примере я покажу, как вы можете реализовать эту логику на JavaScript с использованием DOMParser для обработки HTML-кода.

### Пример реализации на JavaScript

Вы можете использовать следующий код, который будет обрабатывать ваш HTML-код, заменяя инлайн-стили на соответствующие теги:

```javascript
function transformInlineStyles(html) {
    // Парсим HTML
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');

    // Находим все элементы <span>
    const spans = doc.querySelectorAll('span');

    spans.forEach(span => {
        const style = span.getAttribute('style');
        const text = span.innerHTML;

        // Определяем, как заменять элемент <span>
        if (style) {
            const styles = style.split(';').reduce((acc, pair) => {
                const [key, value] = pair.split(':').map(str => str.trim());
                if (key && value) acc[key] = value;
                return acc;
            }, {});

            // Проверяем на жирный текст
            if (styles['font-weight'] === '700') {
                const strong = document.createElement('strong');
                strong.innerHTML = text;
                span.parentNode.replaceChild(strong, span);
            }
            // Проверяем на курсивный текст
            else if (styles['font-style'] === 'italic') {
                const em = document.createElement('em');
                em.innerHTML = text;
                span.parentNode.replaceChild(em, span);
            }
            // Проверяем размер шрифта
            else if (styles['font-size'] && parseFloat(styles['font-size']) >= 18) {
                const h2 = document.createElement('h2');
                h2.innerHTML = text;
                span.parentNode.replaceChild(h2, span);
            }
        }
    });

    // Возвращаем обновленный HTML
    return doc.body.innerHTML;
}

const inputHTML = `<p dir="ltr" style="line-height:1.2;margin-top:0pt;margin-bottom:0pt;">
<span style="font-size:13.999999999999998pt;font-family:Calibri,sans-serif;color:#000000;background-color:#ffffff;font-weight:400;font-style:italic;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">
   Тут текст
</span>
</p>`;

const outputHTML = transformInlineStyles(inputHTML);
console.log(outputHTML);
```

### Объяснение кода:

1. **Парсинг HTML:** Мы используем `DOMParser`, чтобы преобразовать строку HTML в объект, с которым можем работать.

2. **Выбор элементов `<span>`:** Мы используем `querySelectorAll` для выбора всех `<span>` элементов в документе.

3. **Обработка стилей:** С помощью `style.split(';')` мы разбиваем инлайн-стили на пары ключ-значение и сохраняем их в объекте `styles`.

4. **Замена тегов:** В зависимости от значений стилей, мы заменяем `<span>` на соответствующие теги:
   - Если `font-weight` равен `700`, заменяем на `<strong>`.
   - Если `font-style` равен `italic`, заменяем на `<em>`.
   - Если `font-size` больше или равен `18pt`, заменяем на `<h2>`.

5. **Возврат измененного HTML:** После того как все замены выполнены, мы возвращаем обновленный HTML-код.

### Примечания:
- Данный код можно адаптировать и расширить по мере необходимости для других стилей и замен.
- Если требуется обработка других стилей, просто добавьте соответствующие условия в блок `if`.
Вот тебе что-то на подобие парсера на js, который обрабатывает входной HTML-код (span, p) на целевые теги (strong, h2, и т.д.) 

function processHtml(inputHtml) {
  // Создаешь временный DOM для парсинга HTML
  
  const parser = new DOMParser();
  const doc = parser.parseFromString(inputHtml, 'text/html');

  // Обрабатываешь span внутри p
  doc.querySelectorAll('p span[style]').forEach((span) => {
    const style = span.getAttribute('style');
    const fontSizeMatch = style.match(/font-size:\s*([\d.]+)pt/);
    const fontWeightMatch = style.match(/font-weight:\s*(\d+)/);
  // дописать остальные регулярки (font-style и т.д.)

    let newElement;

    if (fontSizeMatch) {
      const fontSize = parseFloat(fontSizeMatch[1]);
      
      if (fontSize >= 18) {
        newElement = document.createElement('h2');
      } else if (fontSize >= 16) {
        newElement = document.createElement('h3');
      }
    }

    if (!newElement && fontWeightMatch) {
      const fontWeight = parseInt(fontWeightMatch[1], 10);
   
      if (fontWeight >= 700) {
        newElement = document.createElement('strong');
      }
    }

    // Если замена нашлась, то создаешь новый элемент
    if (newElement) {
      newElement.textContent = span.textContent;
      span.replaceWith(newElement);
    }
  });

  // Удаляешь лишние стили из p

  doc.querySelectorAll('p').forEach((p) => {
    p.removeAttribute('style');
  });

   return doc.body.innerHTML; // возвращаешь обработанный html
}


const inputHtml = `
<p dir="ltr" style="line-height:1.2;margin-top:0pt;margin-bottom:0pt;">
<span style="font-size:18pt;font-family:Calibri,sans-serif;color:#000000;background-color:#ffffff;font-weight:700;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">
   Тут текст
</span>
</p>`;

const resultHtml = processHtml(inputHtml);
console.log(resultHtml);


Соответственно, если будут дополнительные условия, код можно легко расширить
https://jsfiddle.net/dfhw4eo6/
Похожие вопросы