如何使用正则表达式按HTML标记拆分

时间:2016-10-07 17:44:09

标签: ruby regex

我有一个这样的字符串:

"Energia Elétrica kWh<span class=\"_ _3\"> </span>  10.942 <span class=\"_ _4\"> </span> 0,74999294 <span class=\"_ _5\"> </span>     8.206,39"

我希望通过HTML标记将其拆分,这些标记始终为<span>。我试过像:

my_string.split(/<span(.*)span>/) 

但它没有用,它只能正确匹配第一个元素。

有谁知道我的正则表达式有什么问题?在这个例子中,我期望返回值为:

["Energia Elétrica kWh", "10.942", "0,74999294" ,"8.206,39"]

我想要像strip_tags这样的东西,但不是返回已清理过的字符串,而是通过删除标签来拆分数组。

2 个答案:

答案 0 :(得分:2)

不要使用模式来操纵HTML。这是一个path destined to make you insane

而是使用HTML解析器。 Ruby的标准是Nokogiri

require 'nokogiri'

doc = Nokogiri::HTML::DocumentFragment.parse("Energia Elétrica kWh<span class=\"_ _3\"> </span>  10.942 <span class=\"_ _4\"> </span> 0,74999294 <span class=\"_ _5\"> </span>     8.206,39")

您可以使用text来提取所有文本,但是,如果它是您正在使用的结构化数据,那么通常会很难提取字段,因为文本节点可以连接在一起,从而产生连续的单词,所以要小心:

doc.text # => "Energia Elétrica kWh   10.942   0,74999294       8.206,39"

相反,我们通常从各个节点提取数据:

doc.search('span')[1].next_sibling.text # => " 0,74999294 "
doc.search('span').last.next_sibling.text # => "     8.206,39"

或者,我们遍历节点,然后使用map来获取节点的文本:

doc.search('span').map{ |span| span.next_sibling.text.strip }
# => ["10.942", "0,74999294", "8.206,39"]

我会解决这个问题:

data = [doc.at('span').previous_sibling.text.strip] # => ["Energia Elétrica kWh"]
data += doc.search('span').map{ |span| span.next_sibling.text.strip } 
# => ["Energia Elétrica kWh", "10.942", "0,74999294", "8.206,39"]

或者:

spans = doc.search('span')
data = [
  spans.first.previous_sibling.text,
  *spans.map{ |span| span.next_sibling.text }
].map(&:strip)
# => ["Energia Elétrica kWh", "10.942", "0,74999294", "8.206,39"]

虽然正则表达式通常可以用于初始尝试,但HTML格式的更改可能会破坏模式,强制进行其他更改,然后进行另一次更改,然后再进行另一次更改,直到模式过于复杂,而正确编写的解析器方法通常会非常有弹性并且对问题免疫。

答案 1 :(得分:1)

如果你真的需要使用正则表达式来做到这一点,你几乎已经拥有它了。

irb(main):010:0> string.split(/<span.+?span>/)
=> ["Energia Eltrica kWh", "  10.942 ", " 0,74999294 ", "     8.206,39"]

您只需要?告诉它尽可能少地匹配。