Чтение в фиксированном количестве полей с разделителями трубы на строку? - PullRequest
2 голосов
/ 03 ноября 2010

У меня есть куча файлов с разделителями каналов, которые не были должным образом экранированы для возврата каретки при генерации, и поэтому я не могу использовать символы CR или символы новой строки для разделения строк. Однако я знаю, что в каждой записи должно быть ровно 7 полей.

Разделение полей легко с библиотекой CSV в Ruby 1.9, устанавливающей аргумент 'col_sep', но аргумент 'row_sep' не может быть установлен, потому что у меня есть новые строки внутри полей.

Есть ли способ проанализировать файл с разделителем каналов, используя фиксированное количество полей в качестве разделителя строк?

Спасибо!

Ответы [ 5 ]

1 голос
/ 28 января 2013

Скажем, например, что вы хотели проанализировать все благотворительные фонды в текстовом файле IRS с разделителем каналов.

Допустим, у вас есть модель Charity, в которой есть все те же поля, что и в файле с разделителями каналов.

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

Вы можете создать задачу rake с именем 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

наконец, вы можете запустить этот импорт, набрав следующую команду в вашем приложении rails

 rake import:irs_data
1 голос
/ 03 ноября 2010

Вот один из способов сделать это:

Создайте образец строки из семи слов со встроенной новой строкой в середина строки. Всего три строчки.

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

Процесс, подобный этому:

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

Итак, это показывает, что мы можем перестроить строки.

Притворяясь, что слова на самом деле являются столбцами из файла с разделителями каналов, мы можем заставить код сделать реальную вещь, убрав .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 голосов
/ 20 марта 2011

Попробуйте использовать String#split и Enumerable#each_slice:

result = []
text.split('|').each_slice(7) { |record| result << record }
0 голосов
/ 03 ноября 2010

Просто мысль, но в тестовом геме cucumber есть класс Cucumber::Ast::Table, который можно использовать для обработки этого файла.

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

Тогда я думаю, что это rows метод, который вы можете использовать, чтобы прочитать его.

0 голосов
/ 03 ноября 2010

Вот одна идея, используйте регулярное выражение:

#!/opt/local/bin/ruby

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

Кажется, что это регулярное выражение запутывается в новых строках поля, но я уверен, что вы можете настроить его для правильной работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...