【问题标题】:RegEx: First <br> within a paragraph正则表达式:段落中的第一个 <br>
【发布时间】:2018-11-27 05:33:50
【问题描述】:

如何捕获和删除段落中第一次出现的&lt;br/&gt; 标记。

<p><br/>Hello World</p>

变成:

<p>Hello World</p>

但重要的是,以下内容保持不变:

<p><br/></p>

从包含文本的段落中删除前导 &lt;br&gt; 标记


到目前为止我所拥有的:

preg_replace('/(<p>\s*<br *\/?>(.*?)<\/p>)+/si', '<p>$2</p>', $html);  

虽然这捕获了&lt;p&gt;&lt;br&gt;&lt;/p&gt; 实例...

【问题讨论】:

  • 您想删除第一次出现的
    ,对吗?为此,您只有几种可能性,例如


    Hello World



    Hello World

    。我说的对吗?
  • 是的,你是对的
  • &lt;p&gt;上方是否有父元素?
  • &lt;p&gt;&lt;br/&gt; &lt;/p&gt;也是不应该匹配的情况。
  • 是否应该从&lt;p&gt;&lt;br/&gt; &lt;/p&gt; 中删除&lt;br&gt;?即 &lt;p&gt; 只包含空格的元素?

标签: php html regex laravel


【解决方案1】:

以下是使用 PHP 内置的 DOMDocumentDOMXPath 类的方法:

$html = "<div><p><br/>Hello World</p><p><br/></p><p> <br> </p></div>";
$doc = new DOMDocument();
$doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($doc);
// find <br> within a <p> that has text content
$breaks = $xpath->query("//p[normalize-space()!='']/br");
$breaks = $xpath->query("//p[text()!='']/br");
// and remove them
foreach ($breaks as $br) {
    $br->parentNode->removeChild($br);
}
echo $doc->saveHTML();

请注意,有两行为$breaks 赋值。您应该使用满足您要求的那个:第一个只会从&lt;p&gt;&lt;/p&gt; 之间具有非空白字符的元素中去除&lt;br&gt;,而第二个也会从仅包含&lt;p&gt; 的元素中去除它们空白。不同的效果可以看这个demo

【讨论】:

    【解决方案2】:

    不推荐使用正则表达式解析 html。但只是为了快速和临时的工作,您可以使用此正则表达式来捕获前面有&lt;p&gt; 标记和一些文本的换行符&lt;br/&gt;,并进行前瞻,它不应该立即关闭&lt;/p&gt; 标记。

    <p>.*?\K<br\/>(?!<\/p>)
    

    并将捕获的&lt;br/&gt; 替换为空字符串,从而将其删除。

    说明:

    • &lt;p&gt;.*? --> 以非贪婪的方式匹配段落标签后跟任何字符
    • \K --> 重置任何匹配的内容,因为我们不打算替换它
    • &lt;br\/&gt;(?!&lt;\/p&gt;) --> 匹配一个不紧跟在结束段落标记之后的换行标记,它将被替换为空字符串。

    Demo

    这里是示例 php 代码,

    $html = '<p><br/>Hello World</p>';
    $html = preg_replace('/<p>.*?\K<br\/>(?!<\/p>)/si', '', $html);
    echo $html. "\n";
    
    
    $html = '<p><br/></p>';
    $html = preg_replace('/<p>.*?\K<br\/>(?!<\/p>)/si', '', $html);
    echo $html. "\n";
    

    打印以下输出,

    <p>Hello World</p>
    <p><br/></p>
    

    【讨论】:

      【解决方案3】:

      如果有更多规则,我们可以在preg_replace 中传递数组。在我的解决方案中,模式中的第一个元素将查找带有文本的 &lt;br /&gt;。第二个将只查找&lt;br /&gt; 没有文字。此搜索也是从字符串的开头进行的 (/^..)。

      preg_replace(['/^(<p>\s*(<br *\/?>)([a-zA-Z0-9 ]+)<\/p>)+/si', '/^(<p>\s*(<br *\/?>)<\/p>)+/si'], ['<p>$3</p>', '$0'], $html); 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 2014-08-05
        • 2018-10-13
        • 1970-01-01
        • 1970-01-01
        • 2010-09-12
        • 2011-04-06
        相关资源
        最近更新 更多