【问题标题】:Match unclosed html tags using regex and php使用正则表达式和 php 匹配未关闭的 html 标签
【发布时间】:2015-11-24 20:32:02
【问题描述】:

我正在使用 php 和正则表达式在字符串中查找未闭合的 html 标记:

这是我的字符串:

$s="<div><h2>Hello world<h2><p>It's 7Am where I live<p><div>";

可以看到这里的所有标签都没有关闭。

我想找到所有未关闭的标签,但问题是我的正则表达式也匹配了开始标签。

到目前为止,这是我的正则表达式

/<[^>]+>/i

这是我的 preg_match_all() 函数

preg_match_all("/<[^>]+>/i",$s,$v);

print_r($v);

我需要在我的正则表达式中进行哪些更改以仅匹配未闭合的标签?

 <h2>
 <p>
 <div>

【问题讨论】:

  • 你应该看看tidyphp.net/manual/en/book.tidy.php
  • 为教育目的自行开发的解决方案:构建一个标记器,基本上可以识别标签(打开和关闭)和任何其他文本片段。使用包含已打开标签的堆栈迭代令牌。如果你遇到一个开始标签,把它放在堆栈上。如果遇到结束标签,检查对应的是否在栈顶:如果匹配,则将其从栈中移除;如果不是,则做出相应的反应(例如,抛出错误或丢弃遇到的结束标记)。
  • 这不是正则表达式的用途。
  • @Starkeen:我同意 Brandin 的观点,仅使用正则表达式替换很难解决,我相信您已经在这上面浪费了很多时间。如果我的回答对具体输入没有帮助,请发布这些示例,我很乐意提供帮助。

标签: php regex


【解决方案1】:

您可能没有意识到这一点,但DOMDocument 可以帮助您修复 HTML。

$html = "<div><h2>Hello world<h2><p>It's 7Am where I live<p><div>";
libxml_use_internal_errors(true);

$dom = new DOMDocument();
$dom->loadHTML('<root>' . $html . '</root>', LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);

foreach( $xpath->query('//*[not(node())]') as $node ) {
    $node->parentNode->removeChild($node);
}
echo substr($dom->saveHTML(), 6, -8);

IDEONE demo

结果:&lt;div&gt;&lt;h2&gt;Hello world&lt;/h2&gt;&lt;p&gt;It's 7Am where I live&lt;/p&gt;&lt;/div&gt;

请注意,基于 XPath 的空节点清理是必要的,因为在将 HTML 加载到 DOM 后,DOM 包含空的 &lt;h2&gt;&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;/div&gt; 标记。

&lt;root&gt; 元素被添加到开头,以确保我们可以正确获取根元素。稍后,我们可以使用substr对其进行后期处理。

LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD 标志是必需的,以便不会将 DTD 和其他垃圾添加到 DOM。

【讨论】:

  • 爱你的开场白顺便说一句。然而,一个理想的“坚持者”;很多次我看到包含指向它的链接的答案,只是发现它们在一年左右的时间里是空白的。只是一个简短的旁注。在谷歌上搜索问答时,我经常用那些空白的 ideone URL 找到答案(实际上这周有几个)。至于为什么会这样,我不知道。 干杯
  • @Fred-ii-:是的,不幸的是,它们在不访问时被删除。但是,我在答案中提供了完整的代码。
【解决方案2】:

从根本上说,使用正则表达式很难找到不匹配的标签。您基本上需要将您看到的每个开始标签放入队列中,然后在看到结束标签时将其从队列中弹出。

建议您使用进行 HTML 验证的库。请参阅以下问题:

Remove unmatched HTML tags in a string

How to find the unclosed div tag

PHP get all unclosed HTML tags in string

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多