tener - ¿Cuál es la mejor manera de analizar un archivo delimitado por tabuladores en Ruby?
puede tener caracteristicas no compatibles con csv delimitado por comas (3)
¿Cuál es la mejor (la más eficiente) forma de analizar un archivo delimitado por tabuladores en Ruby?
La biblioteca Ruby CSV le permite especificar el delimitador de campo. Ruby 1.9 usa FasterCSV . Algo como esto funcionaría:
require "csv"
parsed_file = CSV.read("path-to-file.csv", { :col_sep => "/t" })
Las reglas para TSV son en realidad un poco diferentes de CSV. La principal diferencia es que CSV tiene disposiciones para pegar una coma dentro de un campo y luego usar los caracteres de comillas y las comillas de escape dentro de un campo. Escribí un ejemplo rápido para mostrar cómo falla la respuesta simple:
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
Si desea utilizar la biblioteca CSV, podría utilizar un carácter de comillas al azar que no espera ver si su archivo (el ejemplo lo muestra), pero también podría usar una metodología más simple como la clase StrictTsv que se muestra a continuación para obtener el mismo efecto sin tener que preocuparse por las citas de campo.
# 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
La elección de utilizar la biblioteca CSV o algo más estricto depende de quién le envía el archivo y si están esperando adherirse al estricto estándar TSV.
Los detalles sobre el estándar TSV se pueden encontrar en http://en.wikipedia.org/wiki/Tab-separated_values
Me gusta la respuesta de mmmries. SIN EMBARGO, odio la forma en que el rubí elimina cualquier valor vacío del final de una división. Tampoco se está quitando la nueva línea al final de las líneas.
Además, tenía un archivo con nuevas líneas potenciales dentro de un campo. Entonces, reescribí su ''análisis'' de la siguiente manera:
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
Concatena las líneas según sea necesario para obtener una línea completa de datos, y siempre devuelve el conjunto completo de datos (sin posibles entradas nulas al final).