php – обнаружение HTML в строке и перенос с помощью тега кода

У меня проблемы с обработкой HTML в текстовом контенте. Я думаю о методе, который обнаруживает эти теги и обертывает все последовательные одно внутри тегов кода.

Не завершайте меня <p>Hello</p><div class="text">wrap me please!</div><span class="title">wrap me either!</span> Не завершайте меня <h1>End</h1> .

//ожидаемый результат

Не оберните меня <code><p>Hello</p><div class="text">wrap me please!</div><span class="title">wrap me either!</span></code> Не заверните меня <code><h1>End</h1></code> .

Это возможно?

Трудно использовать DOMDocument в этом конкретном случае, поскольку он автоматически переносит текстовые узлы тегами <p> (и добавляет doctype, head, html). Способ состоит в том, чтобы построить шаблон как лексер, используя функцию (?(DEFINE)...) и названные подшаблоны:

 $html = <<<EOD Don't wrap me<p>Hello</p><div class="text">wrap me please!</div><span class="title">wrap me either!</span> Don't wrap me <h1>End</h1> EOD; $pattern = <<<'EOD' ~ (?(DEFINE) (?<self> < [^\W_]++ [^>]* > ) (?<comment> <!-- (?>[^-]++|-(?!->))* -->) (?<cdata> \Q<![CDATA[\E (?>[^]]++|](?!]>))* ]]> ) (?<text> [^<]++ ) (?<tag> < ([^\W_]++) [^>]* > (?> \g<text> | \g<tag> | \g<self> | \g<comment> | \g<cdata> )* </ \g{-1} > ) ) # main pattern (?: \g<tag> | \g<self> | \g<comment> | \g<cdata> )+ ~x EOD; $html = preg_replace($pattern, '<code>$0</code>', $html); echo htmlspecialchars($html); В $html = <<<EOD Don't wrap me<p>Hello</p><div class="text">wrap me please!</div><span class="title">wrap me either!</span> Don't wrap me <h1>End</h1> EOD; $pattern = <<<'EOD' ~ (?(DEFINE) (?<self> < [^\W_]++ [^>]* > ) (?<comment> <!-- (?>[^-]++|-(?!->))* -->) (?<cdata> \Q<![CDATA[\E (?>[^]]++|](?!]>))* ]]> ) (?<text> [^<]++ ) (?<tag> < ([^\W_]++) [^>]* > (?> \g<text> | \g<tag> | \g<self> | \g<comment> | \g<cdata> )* </ \g{-1} > ) ) # main pattern (?: \g<tag> | \g<self> | \g<comment> | \g<cdata> )+ ~x EOD; $html = preg_replace($pattern, '<code>$0</code>', $html); echo htmlspecialchars($html); 

Функция (?(DEFINE)..) позволяет поместить раздел определения внутри шаблона регулярных выражений. Этот раздел определения и именованные подшаблоны внутри ничего не соответствуют, они должны использоваться позже в основном шаблоне.

(?<abcd> ...) определяет подшаблон, который вы можете повторно использовать позже с помощью \g<abcd> . В приведенном выше шаблоне подшаблоны, определенные таким образом:

  • self : описывает самозакрывающийся тег
  • комментарий : для комментариев html
  • cdata : для cdata
  • текст : для текста (все, что не является тегом, комментарием или cdata)
  • tag : для тегов html, которые не являются самозакрытыми

self :
[^\W_] – это трюк, чтобы получить \w без подчеркивания. [^\W]++ представляет имя тега и также используется в подшаблоне tag .
[^>]* означает все, что не равно > 0 или более раз.

Комментарий :
(?>[^-]++|-(?!->))* описывает все возможное содержимое внутри комментария html:

 (?> # open an atomic group [^-]++ # all that is not a literal -, one or more times (possessive) | # OR - # a literal - (?!->) # not followed by -> (negative lookahead) )* # close and repeat the group zero or more times 

cdata :
Все символы между \Q..\E рассматриваются как буквенные символы, специальные символы, такие как [ не нужно экранировать. (Это всего лишь трюк, чтобы сделать рисунок более читаемым).
Содержимое, разрешенное в CDATA, описано так же, как содержание в комментариях html.

текст :
[^<]++ все символы до скобки угла открытия или конца строки.

тег :
Это самый сложный подшаблон. Линии 1 и 3 – это открывающий и закрывающий теги. Обратите внимание, что в строке 1 имя тега захватывается группой захвата. В строке 3 \g{-1} относится к содержимому, согласованному с последней определенной группой захвата («-1» означает «один слева»).
Строка 2 описывает возможное содержимое между открытием и закрывающим тегом. Вы можете видеть, что в этом описании используются не только подшаблоны, определенные ранее, но и текущий подшаблон, чтобы разрешить вложенные теги.

После того, как все элементы установлены и раздел определения закрыт, вы можете легко написать основной шаблон.

У меня проблемы с обработкой HTML в текстовом контенте.

то просто избегайте этого текста:

echo htmlspecialchars($your_text_that_may_contain_html_code);

разбор html с регулярным выражением – это хорошо известный -big- NO!

Это найдет теги вместе с их закрывающими тегами и все между ними:

 <[AZ][A-Z0-9]*\b[^>]*>.*?</\1> 

Возможно, вы сможете захватить эти теги и заменить их тегами вокруг них. Он может не работать с каждым случаем, но вы можете найти его достаточно для своих нужд, если html довольно статичен.