【问题标题】:Replace double line breaks except when tags替换双换行符,除非标签
【发布时间】:2019-02-15 16:39:22
【问题描述】:

我有一些数据库内容作为变量,我想把双换行符变成<p>...</p>

对于单行换行符我想添加<br />

我可以这样做:

$content = nl2br($content, false);
$content = '<p>' . preg_replace('#(<br>[\r\n\s]+){2}#', '</p><p>', $content) . '</p>';

但是,我需要排除具有 h2、h3、h4、ul 并且在 ul 标记内的段落。但我仍然需要在其他 HTML 标签周围添加 p 标签,例如 &lt;strong&gt; &lt;blockquote&gt; &lt;img&gt; &lt;i&gt; &lt;em&gt;&lt;caption&gt;

一个示例文本是:

<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit</h2>

Vivamus vel tempor turpis, <strong>non rutrum quam</strong>. Suspendisse ac rhoncus felis, eget porta lectus. 

Nam vulputate sapien risus, vel vehicula mi volutpat sed. 

<ul>
<li>Sed feugiat nibh at nisl eleifend scelerisque.</li>
<li>Aliquam non maximus ipsum. Aliquam erat volutpat.</li>
</ul>

<h3>Praesent eget diam sit amet leo vehicula sagittis at quis tortor</h3>

Nunc nec sem ac nunc tincidunt aliquam ut nec dolor. Nulla facilisi.

<img alt="xxxx" src="xxx.png" class="xxxxx"/> 

<caption><i>ccccc</i></caption> 

<img alt="xxxx" src="xxx.png" class="xxxxx"/> 

<i>ccccc</i>

<strong>Nunc nec sem ac nunc tincidunt aliquam ut nec dolor. Nulla facilisi.</strong>

Vivamus vel tempor turpis, <strong>non rutrum quam</strong>. Suspendisse ac rhoncus felis, eget porta lectus.

Nunc nec
Nunc nec
Nunc nec

<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Vivamus vel tempor turpis <a href=""></a></p>&mdash; xxxxx (@xxxxxx) <a href="https://twitter.com/xxxx/status/x?ref_src=x">February 15, 2019</a></blockquote>

<script async src="" charset="utf-8"></script>

【问题讨论】:

标签: php regex-negation


【解决方案1】:

我建议不要使用nl2br() 函数——你将在你不想要它们的地方到处注入&lt;br&gt; 标签。

相反,我建议您直接在换行符处执行正则表达式,忽略已经被标签包围的行,如下所示:

(?i)^(?!((&lt;\/|&lt;)(h[1-6]|ul|li|script|blockquote)(\s.+)*&gt;))(.+)(?!(&lt;(\/\3)&gt;))$

如果您想排除更多标签,请将它们放在(h[1-6]|ul|li|script|blockquote) 组中。

让我们分解一下:

  • (?i) 使所有后续匹配不区分大小写
  • ^ 断言行首的位置
  • ?!() 分组是一个负前瞻
  • (&lt;\/|&lt;) 表示我们同时匹配开始或结束标签
  • h[1-6] 匹配 h1、h2、h3 等。
  • (\s.+)*&gt; 匹配开始标签内的额外垃圾,例如,&lt;script xyz&gt;
  • (.+) 是我们想要包裹段落标签的地方
  • &lt;(\/\3)&gt; 中的\3 匹配我们匹配的原始标签,作为结束标签

请注意,上述正则表达式中的 (.+) 是第 5 组,这就是您希望用 &lt;p&gt; 标记包围的内容。您可以使用preg_replace() 中的$5 标记来引用第一组,这样您就可以在该组周围加上一个开始和结束&lt;p&gt; 标记。

这是一个实际应用的例子: https://regex101.com/r/TQGbaq/2

所以您的代码可能如下所示:

$regex = '#(?i)^(?!((<\/|<)(h[1-6]|ul|li|script|blockquote)(\s.+)*>))(.+)(?!(<(\/\3)>))$#';
$content = preg_replace($regex, "<p>$5</p>", $content);

【讨论】:

  • 不错!虽然在某些情况下我确实需要添加

    ...

    我正在更新问题...
  • 另外,如果单行换行我想有
    而不是在它周围添加 p 标签
  • 我更新了我的答案。没有解决您的单个换行符的用例,因为这超出了原始问题的范围,但这应该可以让您完成 90% 的工作。
  • 谢谢。奇怪,它适用于测试中的内容,但不适用于脚本中的变量。 \n 保持不变,就像它无法识别它们来应用正则表达式一样。我尝试在正则表达式之前输出变量并将其复制到测试仪,它在那里工作,但不在我的脚本中!
  • 下次我在电脑前时,我会通过一个 php 脚本为你运行它,我没有测试超出正则表达式的小提琴
【解决方案2】:

您应该在列表中添加 br>,如下所示:

$content = '<p>' . preg_replace('#([\<br\>\r\n\s]{2})#', '</p><p>', $content) . '</p>';

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    相关资源
    最近更新 更多