在 Ruby 中解析以制表符分隔的文件的最佳方法是什么?

在 Ruby 中解析以制表符分隔的文件的最佳(最有效)方法是什么?

29780 次浏览

Ruby CSV 库允许指定字段分隔符。 Ruby 1.9使用 更快的 CSV:

require "csv"
parsed_file = CSV.read("path-to-file.csv", col_sep: "\t")

TSV 的规则实际上与 CSV 略有不同。主要的区别在于 CSV 提供了在字段中添加逗号,然后在字段中使用引号字符和转义引号的规定。我写了一个简单的例子来说明简单的响应是如何失败的:

require 'csv'
line = 'boogie\ttime\tis "now"'
begin
line = CSV.parse_line(line, col_sep: "\t")
puts "parsed correctly"
rescue CSV::MalformedCSVError
puts "failed to parse line"
end


begin
line = CSV.parse_line(line, col_sep: "\t", quote_char: "Ƃ")
puts "parsed correctly with random quote char"
rescue CSV::MalformedCSVError
puts "failed to parse line with random quote char"
end


#Output:
# failed to parse line
# parsed correctly with random quote char

如果你想使用 CSV 库,你可以使用一个随机引用字符,如果你的文件(示例显示了这一点) ,你不希望看到,但你也可以使用一个更简单的方法,如 StrictTsv 类下面显示,以获得相同的效果,而不必担心字段引用。

# The main parse method is mostly borrowed from a tweet by @JEG2
class StrictTsv
attr_reader :filepath
def initialize(filepath)
@filepath = filepath
end


def parse
open(filepath) do |f|
headers = f.gets.strip.split("\t")
f.each do |line|
fields = Hash[headers.zip(line.split("\t"))]
yield fields
end
end
end
end


# Example Usage
tsv = Vendor::StrictTsv.new("your_file.tsv")
tsv.parse do |row|
puts row['named field']
end

使用 CSV 库或其他更严格的选择取决于谁向您发送文件,以及他们是否期望遵守严格的 TSV 标准。

关于 TSV 标准的详细信息可以在 http://en.wikipedia.org/wiki/Tab-separated_values找到

我喜欢回答。但是,我讨厌 Ruby 去掉拆分结束时所有空值的方式。它也没有剥离行尾的换行。

另外,我有一个文件,其中可能包含字段中的换行符:

def parse
open(filepath) do |f|
headers = f.gets.strip.split("\t")
f.each do |line|
myline=line
while myline.scan(/\t/).count != headers.count-1
myline+=f.gets
end
fields = Hash[headers.zip(myline.chomp.split("\t",headers.count))]
yield fields
end
end
end

这会根据需要连接任何行以获得完整的数据行,并且总是返回完整的数据集(末尾没有可能的 nil 条目)。

实际上有两种不同的 TSV 文件。

  1. TSV 文件实际上是 CSV 文件,分隔符设置为 Tab。当您将 Excel 电子表格保存为“ UTF-16Unicode 文本”时,就会得到这个结果。这些文件使用 CSV 引号规则,这意味着字段可能包含制表符和换行符,只要它们被引号,并且文字双引号被写两次。正确解析所有内容的最简单方法是使用 csv gem:

    use 'csv'
    parsed = CSV.read("file.tsv", col_sep: "\t")
    
  2. TSV files conforming to the IANA standard. Tabs and newlines are not allowed as field values, and there is no quoting whatsoever. This is something you will get when you e.g. select a whole Excel spreadsheet and paste it into a text file (beware: it will get messed up if some cells do contain tabs or newlines). Such TSV files can be easily parsed line-by-line with a simple line.rstrip.split("\t", -1) (note -1, which prevents split from removing empty trailing fields). If you want to use the csv gem, simply set quote_char to nil:

    use 'csv'
    parsed = CSV.read("file.tsv", col_sep: "\t", quote_char: nil)