使用\ r,\ n或\ r \ n作为行分隔符逐行读取文件

时间:2015-01-27 03:15:35

标签: ruby

我想逐行处理文件。但是,这些文件具有不同的行分隔符:"\r""\n""\r\n"。我不知道他们使用的是哪种或者他们来自哪种操作系统。

我有两个解决方案:

  1. 使用bash命令将这些分隔符转换为"\n"

    cat file |
    tr '\r\n' '\n' |
    tr '\r' '\n' |
    ruby process.rb
    
  2. 读取整个文件并gsub这些分隔符

    text=File.open('xxx.txt').read
    text.gsub!(/\r\n?/, "\n")
    text.each_line do |line|
      do some thing
    end
    
  3. 但是当文件很大时,第二种解决方案并不好。见reference。有没有其他ruby惯用和有效的解决方案?

1 个答案:

答案 0 :(得分:3)

我建议你先确定行分隔符。我认为你可以通过阅读字符来做到这一点,直到你遇到" \ n"或" \ r" (或到达文件的末尾,在这种情况下,我们可以将" \ n"视为行分隔符)。如果角色" \ n"被发现,我认为是分离器;如果" \ r"发现我试图读下一个字符。如果我能这样做并且它是" \ n",我会返回" \ r \ n"作为分隔符。如果" \ r"是文件中的最后一个字符,或者后面是" \ n"以外的字符,我返回" \ r"作为分隔符。

def separator(fname)
  f = File.open(fname)
  enum = f.each_char
  c = enum.next
  loop do
    case c[/\r|\n/]
    when "\n" then break
    when "\r"
      c << "\n" if enum.peek=="\n"
      break
    end
    c = enum.next
  end
  c[0][/\r|\n/] ? c : "\n"
end

然后逐行处理文件

def process(fname)
  sep = separator(fname)
  IO.foreach(fname, sep) { |line| puts line }
end

我还没有将"\r""\r\n"转换为"\n",但当然你可以轻松地做到这一点。只需打开一个文件进行写入,然后在process中读取每一行,并使用默认行分隔符将其写入输出文件。

让我们尝试一下(为了清楚起见,我会显示separator返回的值):

fname = "temp"

IO.write(fname, "slash n line 1\nslash n line 2\n")
  #=> 30 
separator(fname)                                    
  #=> "\n" 
process(fname)
  # slash n line 1
  # slash n line 2

IO.write(fname, "slash r line 1\rslash r line 2\r", )
  #=> 30 
separator(fname)
  #=> "\r" 
process(fname)
  # slash r line 1
  # slash r line 2

IO.write(fname, "slash r slash n line 1\r\nslash r slash n line 2\r\n")
  #=> 48 
separator(fname)
  #=> "\r\n" 
process(fname)
  # slash r slash n line 1
  # slash r slash n line 2