数组范围被识别为字符串 - 无法转换为整数

时间:2012-11-22 18:03:09

标签: ruby-on-rails ruby web-scraping nokogiri

我在模型中编写了一个函数来刮取网站并将某些属性存储在单独的模型中(story):

def get_content   

          request = HTTParty.get("#{url}")

          doc = Nokogiri::HTML(request.body)

         doc.css("#{anchor}")["#{range}"].each do |entry|

            story = self.stories.new
            story.title = entry.text
            story.url = entry[:href]
            story.save

        end

这使用了Sections变量的urlanchorrange属性。 range属性存储为数组范围 - 即0..211..13 - 然而,我被告知它无法将字符串转换为变量。我已经尝试将range存储为整数和字符串,但都失败了。

我意识到我可以在我的数据库中输入范围的开头和结尾作为两个单独的整数,并放置["#{beginrange}".."#{endrange}"]但这似乎是一种混乱的方式。

还有其他想法吗?非常感谢提前

2 个答案:

答案 0 :(得分:1)

如果您确定range始终是“1..2”(“<Integer >..<Integer>”)之类的字符串,则可以使用eval方法:

在我的IRB控制台中:

1.9.3p0 :032 > (eval "1..2").each { |l| puts l }
1
2
 => 1..2 
1.9.3p0 :033 > (eval "1..2").inspect
 => "1..2" 
1.9.3p0 :034 > (eval "1..2").class
 => Range

在您的情况下:

doc.css("#{anchor}")[eval(range)].each do |entry|
  #...
end

eval有点危险。如果您确定range属性是一个范围作为字符串(验证和正则表达式可以提供帮助),您可以使用eval而无风险。

答案 1 :(得分:0)

我看错了几件事。

["#{beginrange}".."#{endrange}"]创建一系列字符,而不是Array[]所需的整数范围:

beginrange = 1
endrange = 2

["#{beginrange}".."#{endrange}"]
=> ["1".."2"]

[beginrange..endrange]
=> [1..2]

但是,您将所需的数组范围的表示形式存储为字符串。如果我有一个范围的字符串表示,我会使用它:

range_value = '1..2'

[Range.new(*range_value.scan(/\d+/).map(&:to_i))]
=> [1..2]

或者,如果有机会我会遇到一个专属范围:

[Range.new(*range_value.scan(/\d+/).map(&:to_i), range_value['...'])]
=> [1..2]

range_value = '1...2'

[Range.new(*range_value.scan(/\d+/).map(&:to_i), range_value['...'])]
=> [1...2]

当你不能信任Range字符串表示的来源时,这些都是好的,即,值来自其他人创建的表单或文件。如果您拥有传入的值,或者为方便起见,将其作为字符串存储在数据库中,您可以使用eval轻松地重新创建范围:

eval('1..2').class
=> Range
eval('1..2')
=> 1..2
eval('1...2')
=> 1...2

人们害怕eval,因为不明智地使用它是危险的。这并不意味着我们应该避免使用它,相反,我们应该在它安全时使用它。

您可以使用正则表达式检查字符串的格式,如果不接受则引发异常,然后继续:

raise "Invalid range value received" if (!range_value[/\A\d+\s*\.{2,3}\s*\d+\z/])
[eval(range_value)]