simbiat/nl2tag

将换行符转换为不同HTML标签的类

1.3.7+20240616 2024-06-16 08:54 UTC

README

将换行符转换为各种HTML标签(如 brpli)的类。它还可以帮助创建漂亮的变更日志(基于 li 包装)。

为什么?

最初的想法是创建一个 nl2br 的版本,但用于段落。如果你在 Google(或 Stackoverflow)中搜索它,可以找到几个简单的解决方案,但所有这些我都发现至少有一些缺陷。

  1. 它们不会检查是否已经有一个 p 标签在相应的段落周围。这可能会导致额外的段落。至少某些浏览器会将此显示为额外的段落,即 `

    <线1><p><线2>/p>线3</p>

    ` 将导致 3 个段落,这可能不是预期的。
  2. 实际上,有一些标签,按照 phrasing content 的规范,不应该放在 p 中。或者更确切地说,有一些标签,可以放在其中。
  3. 它们会更改标签内的换行符,而你可能希望保留换行符不变。例如,pretextarea 是你通常希望保留换行符的标签。例如,codesampkbdvar 是其他常见的值,但技术上可以是任何设置了 white-space CSS 属性为 prepre-wrappre-linebreak-spaces 的标签。
  4. 它们通常只检查 \r\n 或只是 \r\n,而实际上还有更多表示换行的符号,以及相应的 HTML 实体,它们很容易出现在 HTML 字符串中。

当你处理 HTML 时,这些缺陷可能会成为问题,因此我想找到一种方法来规避这些问题,因此有了这个库。但在概念化初期,我意识到,对于 li 项目和甚至 br,也很有意义去做类似的事情。
我还想能够创建可以很好地用 CSS 样式化的变更日志列表,并且由于这与我们为 nl2li 所拥有的逻辑相同,它是在同一个类中完成的。

限制

  1. 显然,由于处理过程试图变得“智能”,这里有各种各样的检查,它们确实会花费时间。它可能比其他解决方案慢,尽管你很可能不会注意到这一点。
  2. 没有递归。这意味着,如果你有类似
text
<div>text2
text3</div>
text4

的东西

<p>text</p><div>text2<br>text3</div><p>text4</p>

你会得到

<p>text</p><div><p>text2</p><p>text3</p></div><p>text4</p>

而不是

  1. 这是因为递归需要遍历 DOM 树,这意味着转换为 DOMDocument,但转换字符串可能会在不可预测的位置添加额外的标签,因为它试图“修复”可能损坏的文档。这种修改可能会导致与预期截然不同的结果,并且无法预测。考虑到库的预期用途,使用单个级别应该足够。
  2. 我相信,由于这个类依赖于正则表达式,因此通过该类处理时,某些标签和/或换行符的组合可能会导致“损坏”的输出。另一种选择是依赖PHP的DOMDocument及其相关功能。

常量

类包含一些公共常量,以防您在其他代码类中需要类似的东西。

  1. newLinesRegex - 被视为“换行符”的实体列表。它是一个使用|作为分隔符的字符串,可以直接用于正则表达式。
  2. voidElements - 标准HTML5标签的数组,被视为“自闭合”,即不需要闭合标签。
  3. preserveSpacesIn - 标准HTML5标签的数组,通常意味着在其中保留空白。
  4. phrasingContent - 被视为“短语内容”的标准HTML5标签的数组,对此没有其他条件。
  5. flowContent - 与phrasingContent类似,但用于“流内容”,如规范中所述。

选项

该类有一些可以更改的选项(公共变量)。

  1. $preserveSpacesIn - 用于调整您想要在其中保留空白的标签列表。可以是一个空数组,这意味着所有标签内的换行符都可能被相应地替换。
  2. $phrasingContent - 用于调整被视为短语内容的标签列表。不能从相应的常量中删除标签。最可能更新此列表的情况是您有自定义HTML元素。
  3. $flowContent - 用于调整被视为流内容的标签列表。不能从相应的常量中删除标签。最可能更新此列表的情况是您有自定义HTML元素。
  4. $wrapperOnly - 被视为仅作为包装器的标签列表,如table等。它们可以在标签之间有换行符,除非排除在外,否则如果您启用了$situationalBR,您可能会得到过多的<br>标签。
  5. $insideWrappersOnly - 仅在相应包装器内出现的标签列表,其中可以有有意义的换行符,如tdth。专门与$wrapperOnly设置结合使用。
  6. $situationalBR - 布尔标志(默认为true),表示类是否可以在找到换行符时用<br>替换内容中的换行符,并且它不是保留空白的位置。如果名称不够清晰,那是因为无法想出更合适的名称。
  7. $collapseNewLines - 布尔标志(默认为true),表示类是否尝试合并换行符。这意味着<br><br>将替换为<br><br>标签将在<p>标签之间被删除(即<p>1</p><br><p>2</p>将更改为<p>1</p><p>2</p>),并且仅由空白组成的段落也将被删除。我相信在大多数情况下,您会希望启用此功能,但可能存在您想避免它的情况,例如,当您可以在<textarea>内部具有相应的组合时。
  8. $preserveNonBreakingSpace - 布尔标志,表示类是否将保留带有非换行空格的空段落(即&nbsp,在处理过程中转换为正确字符)。如果设置为true(默认为false),则即使$collapseNewLines也设置为true,则类似<p>&nbsp</p>的行也不会被删除。

用法

创建对象

$object = (new \Simbiat\nl2tag);

如有必要,调整设置。设置器可以链接使用。以下示例将添加custom-element作为短语内容,并将只有textarea需要保留空白。

$object->setPhrasingContent(['custom-element'])->setPreserveSpacesIn(['textarea']);

调用适当的函数,同时向其中发送字符串。

$result = $object->nl2p('string');
<div>asdasda</div>
<a href="https://example.com">asdsada</a>
test
test2
<code class="test">
test3<div>afdas</div></code>
<code>tgitjsglsjdgdsjglsd</code>
<span>span</span> after_span
<div class="test">test4</div>
<p>test5</p>
<div>test6
test7</div>

通过nl2p()传递将提供此结果

<div>asdasda</div><p><a href="https://example.com">asdsada</a></p><p>test</p><p>test2</p><code class="test">
test3<div>afdas</div></code><p><code>tgitjsglsjdgdsjglsd</code></p><p><span>span</span> after_span</p><div class="test">test4</div><p>test5</p><div>test6<br>test7</div>

如果通过 nl2br() 处理,将提供以下结果:

<div>asdasda</div><br><a href="https://example.com">asdsada</a><br>test<br>test2<br><code class="test">
test3<div>afdas</div></code><br><code>tgitjsglsjdgdsjglsd</code><br><span>span</span> after_span<br><div class="test">test4</div><br><p>test5</p><br><div>test6<br>test7</div>

如果通过 nl2li() 处理,将提供以下结果:

<ul><li><div>asdasda</div></li><li><a href="">asdsada</a></li><li>test</li><li>test2</li><li><code class="test">
test3<div>afdas</div></code></li><li><code>tgitjsglsjdgdsjglsd</code></li><li><span>span</span> after_span</li><li><div class="test">test4</div></li><li><p>test5</p></li><li><div>test6<br>test7</div></li></ul>

nl2li() 默认将字符串包裹在 ul 中,但你可以传递一个可选的第二个字符串(menuolul),这将允许你更改获取的列表类型。
还有 nl2li() 的一个变体,称为 changelog()。逻辑非常相似,但它还会检查行文本值的第一字符,并为 <li> 添加适当的类。如果字符不是 *+- 之一,则将开始一个子列表(即新的 <ul>),直到遇到另一个类似行或字符串的末尾。
像这样的字符串

* Some general change in logic
List of changes in a specific module:
+ Feature added
- Feature removed
List of changes in another module:
* Some general change

将生成如下 HTML(在标签之间添加空白以提高可读性,实际字符串将不会包含它们):

<ul class="changelog_list">
    <li class="changelog_change">Some general change in logic</li>
    <li class="changelog_sublist_name">List of changes in a specific module:</li>
    <ul class="changelog_sublist">
        <li class="changelog_addition">Feature added</li>
        <li class="changelog_removal">Feature removed</li>
    </ul>
    <li class="changelog_sublist_name">List of changes in another module:</li>
    <ul class="changelog_sublist">
        <li class="changelog_change">Some general change</li>
    </ul>
</ul>

如果进行样式化,你可以得到一个看起来很不错的变更日志,例如,就像你在 这里 看到的那样。