У меня проблемы с обработкой 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 :
[^\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 довольно статичен.