懒洋洋地逐段阅读文件

时间:2014-12-11 10:33:39

标签: ruby lazy-evaluation

我已将一些数据存储在一个文件中,其中每个感兴趣的块都存储在如下段落中:

hello
there

kind

people
of

stack
overflow

我尝试使用以下代码阅读每个段落,但它不起作用:

paragraphs = File.open("hundreds_of_gigs").lazy.to_enum.grep(/.*\n\n/) do |p| 
  puts p
end

正如我所说的正则表达式:"匹配以两个换行结束的任何内容"

我做错了什么?

任何懒惰的方式解决这个问题。方法越精细越好。

3 个答案:

答案 0 :(得分:5)

IO#readline("\n\n")会做你想要的。 FileIO的子类,并且具有所有方法,即使它们未在文件rubydoc页面上声明。

它逐行读取,其中行结束是给定的分隔符。

E.g:

f = File.open("your_file")
f.readline("\n\n") => "hello\nthere\n\n"
f.readline("\n\n") => "kind\n\n"
f.readline("\n\n") => "people\nof\n\n"
f.readline("\n\n") => "stack\noverflow\n\n"

每次调用readline lazy都会从顶部开始读取文件的一行。

或者您可以使用IO#each_line("\n\n")来迭代文件。

E.g:

File.open("your_file").each_line("\n\n") do |line|
  puts line
end

=> "hello\nthere\n\n"
=> "kind\n\n"
=> "people\nof\n\n"
=> "stack\noverflow\n\n"

答案 1 :(得分:2)

自定义解决方案。如果IO#readline(sep)为您完成工作,如@ascar所示,只需使用它。

grouped_lines = open("file.txt").each_line.lazy.map(&:chomp).chunk(&:empty?)
paragraphs = grouped_lines.map { |sep, lines| lines if !sep }.reject(&:nil?)

p paragraphs
#=> <Enumerator::Lazy: #<Enumerator::Lazy:... 

p paragraphs.to_a
#=> [["hello", "there"], ["kind"], ["people", "of"], ["stack", "overflow"]]

答案 2 :(得分:1)

当段落被一个或多个空行分隔时,这是一个惰性方法。我不相信其他解决方案允许段落之间的可变间距。

<强>代码

def paragraphs(fname)
  complete = true
  IO.foreach(fname).with_object([]) do |l,a|
    if l.size > 1
      if complete
        a << l
        complete = false
      else
        a[-1] << l
      end
    else
      complete = true
    end
  end
end

示例

str = "hello\nthere\n\nkind\n\n\npeople\nof\n\n\n\n\nstack\noverflow"
fname = 'tmp'
File.write(fname, str)

paragraphs(fname)
  #=> ["hello\nthere\n", "kind\n", "people\nof\n", "stack\noverflow"]