php - 检测字符串中的 HTML 并用代码标签包装

2024-01-18

我在处理文本内容中的 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);

The (?(DEFINE)..)功能允许将定义部分放入正则表达式模式中。此定义部分和其中的命名子模式不匹配任何内容,它们稍后将在主模式中使用。

(?<abcd> ...)定义一个您可以稍后重用的子模式\g<abcd>。在上面的模式中,以这种方式定义的子模式是:

  • self: 描述一个自闭合标签
  • comment: 用于 html 注释
  • cdata:对于 cdata
  • text: 用于文本(除标签、注释或 cdata 以外的所有内容)
  • tag: 对于非自闭合的 html 标签

self:
[^\W_]是一个获得的技巧\w没有下划线。[^\W]++代表标签名称并且也在tag子模式。
[^>]*意味着所有不是>零次或多次。

comment:
(?>[^-]++|-(?!->))*描述 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 注释中的内容相同。

text:
[^<]++直到左尖括号或字符串末尾的所有字符。

tag:
这是最有趣的子模式。第 1 行和第 3 行是开始标签和结束标签。请注意,在第 1 行中,标记名称是使用捕获组捕获的。在第 3 行中,\g{-1}指的是最后定义的捕获组匹配的内容(“-1”表示“左边一个”)。
第 2 行描述了开始标签和结束标签之间可能的内容。您可以看到,此描述不仅使用之前定义的子模式,还使用当前子模式本身来允许嵌套标签。

一旦设置了所有项目并关闭了定义部分,您就可以轻松编写主要模式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

php - 检测字符串中的 HTML 并用代码标签包装 的相关文章

随机推荐