2010-11-03 21 views
2

J'ai un tas de fichiers délimités par des tuyaux qui n'ont pas été correctement échappés pour les retours chariot quand ils sont générés, et donc je ne peux pas utiliser les caractères CR ou newline pour délimiter les lignes. Je sais cependant que chaque enregistrement doit avoir exactement 7 champs.Lecture dans un nombre fixe de champs délimités par une ligne par ligne?

Le fractionnement des champs est facile avec la bibliothèque CSV de Ruby 1.9 qui définit l'argument 'col_sep', mais l'argument 'row_sep' ne peut pas être défini car j'ai des retours à la ligne dans les champs.

Existe-t-il un moyen d'analyser un fichier délimité par des barres à l'aide d'un nombre fixe de champs en tant que délimiteur de ligne?

Merci!

+0

pouvez-vous donner un exemple de chaîne délimitée. – Trez

Répondre

1

est ici une façon de le faire:

Construire une chaîne d'échantillon de sept mots, avec une nouvelle ligne intégrée au milieu de la chaîne. Il y a trois lignes de valeur.

text = (["now is the\ntime for all good"] * 3).join(' ').gsub(' ', '|') 
puts text 
# >> now|is|the 
# >> time|for|all|good|now|is|the 
# >> time|for|all|good|now|is|the 
# >> time|for|all|good 

processus comme celui-ci:

lines = [] 
chunks = text.gsub("\n", '|').split('|') 
while (chunks.any?) 
    lines << chunks.slice!(0, 7).join(' ') 
end 

puts lines 
# >> now is the time for all good 
# >> now is the time for all good 
# >> now is the time for all good 

Alors, qui montre que nous pouvons reconstruire les lignes.

Prétendre que les mots sont en fait les colonnes du fichier délimité par des tuyaux, nous pouvons faire le code faire la vraie chose en prenant le .join(' '):

while (chunks.any?) 
    lines << chunks.slice!(0, 7) 
end 

ap lines 
# >> [ 
# >>  [0] [ 
# >>   [0] "now", 
# >>   [1] "is", 
# >>   [2] "the", 
# >>   [3] "time", 
# >>   [4] "for", 
# >>   [5] "all", 
# >>   [6] "good" 
# >>  ], 
# >>  [1] [ 
# >>   [0] "now", 
# >>   [1] "is", 
# >>   [2] "the", 
# >>   [3] "time", 
# >>   [4] "for", 
# >>   [5] "all", 
# >>   [6] "good" 
# >>  ], 
# >>  [2] [ 
# >>   [0] "now", 
# >>   [1] "is", 
# >>   [2] "the", 
# >>   [3] "time", 
# >>   [4] "for", 
# >>   [5] "all", 
# >>   [6] "good" 
# >>  ] 
# >> ] 
0

est ici une idée, utilisez une expression régulière:

#!/opt/local/bin/ruby 

fp = File.open("pipe_delim.txt") 
r1 = /.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|/m 
results = fp.gets.scan(r1) 
results.each do |result| 
    puts result 
end 

Ce regex semble trébucher sur les nouvelles lignes dans un champ, mais je suis sûr que vous pouvez modifier pour fonctionner correctement.

0

Juste une pensée, mais le petit bijou d'essai cucumber a une Cucumber::Ast::Table classe que vous pourriez utiliser pour traiter ce fichier.

Cucumber::Ast::Table.new(File.read(file)) 

Je pense que c'est la méthode rows vous pouvez utiliser pour lire.

0

Essayez d'utiliser String#split et Enumerable#each_slice:

result = [] 
text.split('|').each_slice(7) { |record| result << record } 
1

Dites par exemple que vous vouliez analyser tous les organismes de bienfaisance dans le fichier txt IRS qui est délimité par des tuyaux.

Supposons que vous ayez un modèle appelé Charity qui a tous les mêmes champs que votre fichier délimité par des tuyaux.

class Charity < ActiveRecord::Base 
    # http://apps.irs.gov/app/eos/forwardToPub78DownloadLayout.do 
    # http://apps.irs.gov/app/eos/forwardToPub78Download.do 
    attr_accessible :city, :country, :deductibility_status, :deductibility_status_description, :ein, :legal_name, :state 
end 

Vous pouvez faire une tâche de râteau appelé import.rake

namespace :import do 

    desc "Import Pipe Delimted IRS 5013c Data " 
    task :irs_data => :environment do 

    require 'csv' 

    txt_file_path = 'db/irs_5013cs.txt' 
    results = File.open(txt_file_path).readlines do |line| 
     line = line.split('|').each_slice(7) 
    end 

    # Order Field Notes 
    # 1 EIN Required 
    # 2 Legal Name Optional 
    # 3 City Optional 
    # 4 State Optional 
    # 5 Deductibility Status Optional 
    # 6 Country Optional - If Country is null, then Country is assumed to be United States 
    # 7 Deductibility Status Description Optional 

    results.each do |row| 
     row = row.split('|').each_slice(7).to_a.first 
     #ID,Category,Sub Category,State Standard 
     Charity.create!({ 
     :ein        => row[0], 
     :legal_name      => row[1], 
     :city        => row[2], 
     :state       => row[3], 
     :deductibility_status    => row[4], 
     :country       => row[5], 
     :deductibility_status_description => row[6] 
     }) 
    end 
    end 
end 

enfin, vous pouvez exécuter cette importation en tapant suivant à la ligne de commande de votre rails app

rake import:irs_data