在Javascript中,有没有一种简单的方法将带有多个<br/>标签的HTML转换为正确的<p>标签?

3

假设我有一堆像下面这样的HTML:

bla bla bla long paragraph here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>

有没有一种简单的方法可以使用Javascript将其转换为正确语义的<p>标签?例如:
<p>
  bla bla bla long paragraph here
</p>
<p>
  bla bla bla more paragraph text
</p>

输出间距不重要,理想情况下它可以适应任何输入间距。

我在考虑是否可以使用正则表达式来解决这个问题,但在此之前,我想确保a)避免麻烦和b)没有其他更好的解决方法 - 我已经尝试过谷歌搜索,但还没有找到合适的答案。

感谢您提供的任何建议!


真的很棒 - 我想我会得到一些正确方向的指针,但我绝对没有预料到会有两个完全不同的编码解决方案。我需要一两天时间来实现它,但我会确保回报并告诉你我最终使用了什么方法。 - Rufo Sanchez
4个回答

7

我感到无聊了。我相信还需要进行优化/调整。使用了一点jQuery来实现它的效果。在FF3中工作正常。而你的问题的答案是:没有非常“简单”的方法 :)

$(function() {
  $.fn.pmaker = function() {
    var brs = 0;
    var nodes = [];

    function makeP()
    {
      // only bother doing this if we have nodes to stick into a P
      if (nodes.length) {
        var p = $("<p/>");
        p.insertBefore(nodes[0]);  // insert a new P before the content
        p.append(nodes); // add the children        
        nodes = [];
      }
      brs=0;
    }

    this.contents().each(function() {    
      if (this.nodeType == 3) // text node 
      {
        // if the text has non whitespace - reset the BR counter
        if (/\S+/.test(this.data)) {
          nodes.push(this);
          brs = 0;
        }
      } else if (this.nodeType == 1) {
        if (/br/i.test(this.tagName)) {
          if (++brs == 2) {
            $(this).remove(); // remove this BR from the dom
            $(nodes.pop()).remove(); // delete the previous BR from the array and the DOM
            makeP();
          } else {
            nodes.push(this);
          }
        } else if (/^(?:p)$/i.test(this.tagName)) {
          // these tags for the P break but dont scan within
          makeP();
        } else if (/^(?:div)$/i.test(this.tagName)) {
          // force a P break and scan within
          makeP();
          $(this).pmaker();
        } else {
          brs = 0; // some other tag - reset brs.
          nodes.push(this); // add the node 
          // specific nodes to not peek inside of - inline tags
          if (!(/^(?:b|i|strong|em|span|u)$/i.test(this.tagName))) {
            $(this).pmaker(); // peek inside for P needs            
          }
        } 
      } 
    });
    while ((brs--)>0) { // remove any extra BR's at the end
      $(nodes.pop()).remove();
    }
    makeP();
    return this;
  };

  // run it against something:
  $(function(){ 
    $("#worker").pmaker();
  });

我测试的HTML部分如下:

<div id="worker">
bla bla bla long <b>paragraph</b> here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>
this text should end up in a P
<div class='test'>
  and so should this
  <br/>
  <br/>
  and this<br/>without breaking at the single BR
</div>
and then we have the a "buggy" clause
<p>
  fear the real P!
</p>
and a trailing br<br/>
</div>

结果如下:

<div id="worker"><p>
bla bla bla long <b>paragraph</b> here
</p>
<p>
bla bla bla more paragraph text
</p>
<p>
this text should end up in a P
</p><div class="test"><p>
  and so should this
  </p>
  <p>
  and this<br/>without breaking at the single BR
</p></div><p>
and then we have the a "buggy" clause
</p><p>
  fear the real P!
</p><p>
and a trailing br</p>
</div>

1
如果您喜欢这个答案,请为roboprog点赞,他是它的灵感来源。 - gnarf

5

扫描封闭元素的每个子元素和文本。每当遇到一个“br”元素时,创建一个“p”元素,并将所有待处理的内容附加到其中。重复此操作。

不要忘记删除要移动到新“p”元素的内容。

我发现这个库(prototype.js)在这种情况下非常有用。


4

我假设您不允许任何其他的操作。有时,您需要保留单个换行符(不是所有的 <br /> 元素都是错误的),并且只想将双重实例的 <br /> 转换为段落分隔符。

为此,我会:

  1. 删除所有换行符
  2. 将整个内容包装在一个段落中
  3. </p>\n<p> 替换 <br /><br />
  4. 最后,删除可能生成的空的 <p></p> 元素

因此,代码可能看起来像这样:

var ConvertToParagraphs = function(text) {
    var lineBreaksRemoved = text.replace(/\n/g, "");
    var wrappedInParagraphs = "<p>" + lineBreaksRemoved + "</p>";
    var brsRemoved = wrappedInParagraphs.replace(/<br[^>]*>[\s]*<br[^>]*>/gi, "</p>\n<p>");
    var emptyParagraphsRemoved = brsRemoved.replace(/<p><\/p>/g, "");
    return emptyParagraphsRemoved;
}

注意: 我写的非常详细以展示过程,当然你可以简化它。

这将转换您的样本:

bla bla bla long paragraph here
<br/>
<br/>
bla bla bla more paragraph text
<br/>
<br/>

Into:

<p>bla bla bla long paragraph here</p>
<p>bla bla bla more paragraph text</p>

但是它这样做时不会删除任何您可能想要保留的<br />元素。

0

我会分几个阶段来完成:

  1. 正则表达式:将所有 br 标签转换为换行符。
  2. 正则表达式:删除所有空格。
  3. 正则表达式:将多个换行符转换为单个换行符。
  4. 在结果上使用 Array.split('\n')。

这样应该会得到一个包含所有“真实”段落的数组(理论上)。然后您只需遍历它并将每行包装在 p 标签中即可。


这可能会导致问题,因为在HTML中有多个换行符是无关紧要的。第三步可能会创建一系列不需要的段落。 - nickf
有时候你实际上想要一个单独的 <br> 元素保留下来,而你的步骤1会将其移除。 - Jason Berry
@nickf:步骤 3 将多个换行符转换为单个换行符,所以我不太知道你的意思。@Jason:确实如此。上面发布的基于节点的解决方案更加通用。 - shuckster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接