【问题标题】:Regex PHP find and match HTML tags with specific data-attributes正则表达式 PHP 查找并匹配具有特定数据属性的 HTML 标记
【发布时间】:2019-04-12 23:20:09
【问题描述】:

我正在尝试解析 CTP 文件(其中包含 HTML 和 PHP 标记的 CakePHP 模板)并希望将所有 HTML 标记与特定数据属性 (data-edit="true") 匹配。每个带有 data-edit="true" 的标签必须有一个 data-type="..." 和 data-name="..." 属性。我想在(命名的)组中捕获这些属性,所以我可以在我的代码中使用它们。 到目前为止,我有以下正则表达式:

\<(?<tagname>\w+).*?(?>data\-edit="true").*?\>(?<content>.*?)\<\/(?&tagname)\>

以下是它应该匹配的一些标签示例:

<h4 data-type="text" data-edit="true" data-name="SomeName">Some content, with or without newlines.</h4>

<span data-edit="true" data-type="wysiwyg" data-name="Beoordeling">Some text 
with <strong>tags</strong> and newlines in it that 
should not break the parser.</span>

从上面的示例中,我希望正则表达式返回数据类型和数据名称标签的内容,当然还有内容(标签之间)本身。

数据属性可以以任何顺序出现,并且标签中可能存在其他属性(例如类)。到目前为止,我已经设法仅获取具有 data-edit="true" 属性的标签的内容,但是当有换行符时,匹配会中断。我也无法捕获其他数据属性。

我想达到什么目标?我知道正则表达式不是解析 HTML 的首选方式,但由于这是一个包含各种其他标签的 CTP 文件,我不能使用 XML 解析器。

编辑:示例代码:https://regex101.com/r/nF6a96/2

【问题讨论】:

  • "因为这是一个包含各种其他标签的 CTP 文件,所以我不能使用 XML 解析器" ... XML 解析器绝对可以对于您给出的两个示例,它可能会失败的地方是 HTML 标记没有以 XML 方式关闭(例如 &lt;br&gt;)(尽管 DOMDocument 可以应付)或者嵌入了 PHP @987654327 @)。
  • @mickmackusa:更新了问题,包含了示例代码的链接

标签: php regex


【解决方案1】:

XPath 是一个非常棒的多功能工具。您的逻辑无缝转移到 xpath 查询中,该查询在未来易于构建、读取和维护。

此外,XPath 优于正则表达式,因为无论属性的顺序如何,它都能成功匹配符合条件的元素。只需一个 preg_ 调用,Regex 就很难做到这一点。

以下内容将通过循环验证、提取和存储仅一个查询的结果。

代码:(Demo)

$dom=new DOMDocument; 
libxml_use_internal_errors(true);  // for malformed html warning suppression
$dom->loadHTML($text, LIBXML_NOENT);
//libxml_clear_errors();             // for  warning suppression
$xpath = new DOMXPath($dom);

foreach ($xpath->query("//*[@data-edit='true' and @data-type and @data-name]") as $node) {
    $results[] = [
                    'type' => $node->getAttribute('data-type'),
                    'name' => $node->getAttribute('data-name'),
                    'text' => $node->textContent
                 ];
}
var_export($results);

输出:

array (
  0 => 
  array (
    'type' => 'wysiwyg',
    'name' => 'Beoordeling',
    'text' => 'We beoordelen uw aanvraag en                                        berichten u over de acceptatie daarvan.',
  ),
  1 => 
  array (
    'type' => 'text',
    'name' => 'Bellen',
    'text' => 'We bellen u voor een afspraak.',
  ),
  2 => 
  array (
    'type' => 'text',
    'name' => 'Technisch specialist',
    'text' => 'Technisch specialist neemt bij u alles nog even door.',
  ),
)

【讨论】:

  • 哇@mickmackusa,这效果好多了,谢谢!
【解决方案2】:

您应该避免使用正则表达式解析 html,但由于这是在标签内查找属性的情况,而不是标签的某些嵌套场景,因此您可以在此处使用正则表达式进行快速验证。

您需要使用前瞻来确保标签确实包含您正在寻找的所有三种属性。你可以使用这个正则表达式,

<(\w+)(?=.*?data-edit="true")(?=.*?data-type="[^"]*")(?=.*?data-name="[^"]*")[^>]*?>.*?<\/\1>

说明:

  • &lt;(\w+) --> 匹配一个标签并捕获 group1 中的标签名以匹配结束标签的末尾
  • (?=.*?data-edit="true") --> 前瞻并确保存在数据编辑属性
  • (?=.*?data-type="[^"]*") --> 前瞻并确保存在数据类型属性
  • (?=.*?data-name="[^"]*") --> 前瞻并确保存在 data-name 属性
  • [^&gt;]*?&gt; --> 匹配输入和结束标签的其余部分
  • .*? --> 匹配开始和结束标签内的任何文本
  • &lt;\/\1&gt; --> 匹配结束标签

Demo

【讨论】:

  • 谢谢@Pushpesh!我已将正则表达式更改为: [^"]*) ")(?=.*?data-name="(?[^"]*)")[^>]*?>(?.*?) 这样做正是我想要的!
  • @mickmackusa:我给出的这个正则表达式旨在验证标签是否符合预期标准。要捕获单个部分,可能需要一个或多个正则表达式,具体取决于属性在标签中的显示方式。如果它们总是以相同的顺序出现,那么可以使用单个正则表达式捕获它,否则将需要多个正则表达式。
  • @mickmackusa 您应该停止尝试通过宣传自己的答案来降低此答案的价值。
猜你喜欢
  • 2012-02-18
  • 2015-03-15
  • 2013-06-16
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
相关资源
最近更新 更多