5

我正在尝试从<p>标签之间的 HTML 片段中删除空格

<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>

<p> </p>如您所见,标签之间总是有一个空格。

<br>问题是在将字符串保存到我的数据库时,空格会创建标签。类似stripgsub仅删除节点中的空格的方法,导致:

<p>FooBar</p> <p>barbarbar</p> <p>bla</p>

而我想要:

<p>Foo Bar</p><p>bar bar bar</p><p>bla</p>

我正在使用:

  • Nokogiri 1.5.6
  • 红宝石 1.9.3
  • 导轨

更新:

偶尔会有<p>标签的子节点产生同样的问题:

示例代码

注意:代码通常在一行中,我重新格式化它,因为否则它将无法忍受......

<p>
  <p>
    <strong>Selling an Appartment</strong>
  </p>
  <ul>
    <li>
      <p>beautiful apartment!</p>
    </li>
    <li>
      <p>near the train station</p>
    </li>
    .
    .
    .
  </ul>
  <ul>
    <li> 
      <p>10 minutes away from a shopping mall </p>
    </li>
    <li>
      <p>nice view</p>
    </li>
  </ul>
  .
  .
  .
</p>

我将如何去除那些空白?

解决方案

原来我用这个gsub方法搞砸了,没有进一步调查使用gsubwith regex...

简单的解决方案是添加

data = data.gsub(/>\s+</, "><")

它删除了所有不同类型节点之间的空白......正则表达式ftw!

4

4 回答 4

2

这就是我编写代码的方式:

require 'nokogiri'

doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>
EOT

doc.search('p, ul, li').each { |node| 
  next_node = node.next_sibling
  next_node.remove if next_node && next_node.text.strip == ''
}

puts doc.to_html

结果是:

<p>Foo Bar</p><p>bar bar bar</p><p>bla</p>

分解它:

doc.search('p')

仅查找<p>文档中的节点。Nokogiri 从 中返回 NodeSet search,如果没有匹配则返回 nil。代码在 NodeSet 上循环,依次查看每个节点。

next_node = node.next_sibling

获取指向当前<p>节点之后的下一个节点的指针。

next_node.remove if next_node && next_node.text.strip == ''

next_node.removenext_node如果下一个节点不是 nil 并且其文本在剥离时不为空,则从 DOM中删除当前节点,换句话说,如果节点只有空格。

如果应该从文档中删除所有 TextNode,还有其他技术可以仅定位 TextNode。这是有风险的,因为它最终可能会删除标签之间的所有空白,从而导致连续句子和连词,这可能不是您想要的。

于 2013-05-07T19:59:37.653 回答
0

第一个解决方案可以是删除空文本节点,针对您的具体情况执行此操作的快速方法可以是:

require 'nokogiri'
doc = Nokogiri::HTML("<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>")
doc.css('body').first.children.map{|node| node.to_s.strip}.compact.join

这不适用于按原样嵌套的元素,但应该为您提供一个良好的开始路径。

更新:

您实际上可以通过以下方式进行一些优化:

require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse("<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>")
doc.children.map{|node| node.to_s.strip}.compact.join
于 2013-05-07T12:00:21.723 回答
0

这是您可以寻找的所有可能的任务,这些任务在解析输出时处理不必要的空格(包括 unicode 空格)。

html = "<p>A paragraph.<em>&nbsp; &nbsp;</em> <br><br><em>&nbsp; &nbsp; &nbsp; 
</em></p><p><em>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </em>
</p><p><em>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 
&nbsp; &nbsp;&nbsp; </em><strong><em>\" Quoted Text \"&nbsp; </em></strong></p>
<ul><li><p>List 1</p></li><li><p>List 2</p></li><li><p>List 3 </p>
<p><br></p><p><br><em> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</em><br>
A text content.<br><em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </em></p></li></ul>"

doc = Nokogiri::HTML.fragment(html)

doc.traverse { |node|
  # removes any whitespace node
  node.remove if node.text.gsub(/[[:space:]]/, '') == ''

  # replace mutiple consecutive spaces with single space
  node.content = node.text.gsub(/[[:space:]]{2,}/, ' ') if node.text?
}

# Gives you html without any text node including <br> or multiple spaces anywhere in the text of html
puts doc.to_html

# Gives text of html, concatenating li items with a space between them
# By default li items text are concatenated without the space     
Nokogiri::HTML(doc.to_html).xpath('//text()').map(&:text).join(' ')

#Output 
# "A paragraph. \" Quoted Text \"  \n List 1 \n List 2 \n \n List 3  \n A text content. \n \n"

# To Remove newline character '\n'
Nokogiri::HTML(doc.to_html).xpath('//text()').map(&:text).join(' ').gsub(/\n+/,'')

#Output
# "A paragraph. \" Quoted Text \"   List 1  List 2   List 3   A text content."

注意:如果您没有使用fragment完整的html文档,那么您可能必须traverse使用其他功能(如search.

于 2021-01-06T10:30:17.257 回答
-3

data.squish 做同样的事情并且更具可读性。

于 2016-05-16T21:08:07.873 回答