1

我有以下代码可以解析 HTML 文本并修剪(或去除)空的段落。它类似于.stripString 对象。

doc = Nokogiri::HTML::DocumentFragment.parse(html)

# repetition that I want to collapse
doc.css('p').each do |p|
  if all_children_are_blank?(p)
    p.remove
  else
    break
  end
end

# repetition that I want to collapse
doc.css('p').reverse_each do |p|
  if all_children_are_blank?(p)
    p.remove
  else
    break
  end
end

doc.to_s.strip

有没有更优雅的方法来防止我用注释标记的代码被复制并遵守代码重用原则?

这是我想出的,但我对它还不满意,想看看是否有更好的东西:

doc = Nokogiri::HTML::DocumentFragment.parse(html)

doc.css('p').each do |p|
  if stop(p) then break end
end

doc.css('p').reverse_each do |p|
  if stop(p) then break end
end

doc.to_s.strip

def self.stop(p)
  if all_children_are_blank?(p)
    p.remove
    false
  else
    true
  end
end
4

3 回答 3

1

如果我了解您要查找的内容,您会想要一种更简单的方法来迭代您正在查看的元素,以删除空白p元素。

这是折叠您所写内容的简单方法,无需做很多不同的事情:

doc.tap do |d|
  [:each, :reverse_each].each do |sym|
    d.css("p").public_send(sym) do |p|
      if blank_children?(p)
        p.remove
      else
        break
      end
    end
  end
end.to_s.strip

我没有对此进行测试,因此您可能需要对其进行一些调整。如果这是生产代码,我可能会将其分解为一个或多个方法调用以保持清晰。

于 2012-12-06T22:19:08.517 回答
1

怎么样:

[*doc.css('p'), *doc.css('p').reverse].each do |p|
  if stop(p) then break end
end

在这种情况下,splat 运算符 ("*") 将两个列表展开为一个数组,其中元素先升序,然后降序。然后你只需遍历整个组。


编辑:由于break语句跳到所有内容的末尾,这将无法正常工作。因此,恕我直言,这样做的正确方法是将块分配给一个变量。而且您也可以消除该stop功能,因为无论如何您都在消除代码的重复:

remover = lambda do |p|
  if all_children_are_blank? p
    p.remove
  else
    break
  end
end

doc.css('p').to_a.each(&remover).reverse_each(&remover)

希望这可以帮助。

于 2012-12-06T23:27:54.457 回答
1

也许是这样的:

puts "removing a top p" until stop(doc.at('p'))
puts "removing a bottom p" until stop(doc.search('p').last)

要不就:

puts "removing a p" until stop(doc.at('p')) && stop(doc.search('p').last)
于 2012-12-07T02:51:19.977 回答