我想逐行处理文件。但是,这些文件具有不同的行分隔符:"\r"
,"\n"
或"\r\n"
。我不知道他们使用的是哪种或者他们来自哪种操作系统。
我有两个解决方案:
使用bash命令将这些分隔符转换为"\n"
。
cat file |
tr '\r\n' '\n' |
tr '\r' '\n' |
ruby process.rb
读取整个文件并gsub这些分隔符
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
do some thing
end
但是当文件很大时,第二种解决方案并不好。见reference。有没有其他ruby惯用和有效的解决方案?
答案 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