php - 检测字符串中的HTML并使用代码标记进行换行

时间:2014-04-03 14:30:44

标签: php html regex string

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

这可能吗?

3 个答案:

答案 0 :(得分:4)

在这种特定情况下很难使用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);

(?(DEFINE)..)功能允许将定义部分放在正则表达式模式中。这个定义部分和里面的命名子模式没有任何匹配,它们将在稍后的主模式中使用。

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

  • 自我:描述自我结束标记
  • 评论:用于HTML评论
  • cdata :for cdata
  • 文字:用于文字(所有不是标签,评论或cdata)
  • 标记:用于非自动关闭的HTML标记

<强>自
[^\W_]是获取\w而没有下划线的技巧。 [^\W]++代表标记名称,也在tag子模式中使用 [^>]*表示所有不是>零次或多次。

<强>注释
(?>[^-]++|-(?!->))*描述了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}指的是最后定义的捕获组匹配的内容(&#34; -1&#34;表示&#34;左边一个&#34;)。图2描述了开始标记和结束标记之间的可能内容。您可以看到此描述不仅使用之前定义的子模式,而且使用当前子模式本身来允许嵌套标记。

设置完所有项目并关闭定义部分后,您可以轻松编写主模式。

答案 1 :(得分:0)

我在处理文本内容中的HTML方面遇到了麻烦。

然后只是逃避那个文字:

echo htmlspecialchars($your_text_that_may_contain_html_code);

使用正则表达式解析html是well-known - big- NO!

答案 2 :(得分:0)

这将找到标签及其结束标签,以及介于两者之间的所有内容:

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

您可以捕获这些标记并将其替换为周围的标记。它可能不适用于所有情况,但如果html是相当静态的,您可能会发现它足以满足您的需求。