【问题标题】:Lazily reading file paragraph by paragraph懒惰地逐段阅读文件
【发布时间】:2014-12-11 10:33:38
【问题描述】:

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

hello
there

kind

people
of

stack
overflow

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

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

我想说的是:“匹配任何以两个换行符结尾的东西”

我做错了什么?

任何解决此问题的懒惰方式都值得赞赏。方法越简洁越好。

【问题讨论】:

  • 这里描述了非懒惰的方式:codereview.stackexchange.com/questions/37696/…
  • File#each_line 完全满足您的需求
  • 呃,我很确定它读的是行而不是段落。
  • @TheUnfunCat 确实如此,只需将 "\n\n" 作为参数传递

标签: ruby lazy-evaluation


【解决方案1】:

IO#readline("\n\n") 会做你想做的事。 FileIO 的子类,并且拥有它的所有方法,即使它们没有在文件 ruby​​doc 页面上说明。

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

例如:

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") 来遍历文件。

例如:

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"

【讨论】:

  • 这看起来是最简单的方法。问题:如果有两个以上的“\n”怎么办?
  • 分隔符基本上可以是任何东西,您甚至可以动态更改它。那里没有限制。它只读取一行,直到找到分隔符或 EOF。下一个电话甚至可以是另一个分隔符。如果该示例中有 4 个 \n,您将得到一个空段落。
  • 对于前pythonistas:"\n\n" != '\n\n'
  • @TheUnfunCat '\n\n' == "\\n\\n" 单引号将反斜杠视为文字
【解决方案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"]]

【讨论】:

    【解决方案3】:

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

    代码

    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"]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      • 1970-01-01
      • 2020-04-05
      • 1970-01-01
      相关资源
      最近更新 更多