0

私はこのようなプレーンテキストの表を持っています。データがそれぞれの列にまとめられるように、結果行をグループ化する必要があります。

文字列(1行)をスペースで分割すると、次のような配列が得られます。

["2", "1/47", "M4044", "25:03*", "856", "12:22", "12:41", "17.52", "Some", "Name", "Yo", "Prairie", "Inn", "Harriers", "Runni", "25:03"]

また、2つのスペースに分割することもできます。これにより、私は近くになりますが、名前でわかるように、一貫性がありません。

["2", " 1/47", "M4044", " 25:03*", "856", " 12:22", " 12:41", "17.52 Some Name Yo", "", "", "", "", "", "", "Prairie Inn Harriers Runni", " 25:03 "]

結合するインデックスを指定することはできますが、このように数千のファイルを取得する必要があり、列が常に同じ順序になるとは限りません。

1つの定数は、列データが列名とデータの間の仕切り(====)より長くなることはないということです。私はこれを自分の利益のために使おうとしましたが、いくつかの抜け穴を見つけました。

名前の列に何が残っているのか、他の「単語」の列に何が残っているのかを検出するアルゴリズムを作成する必要があります。何かご意見は?

4

4 に答える 4

4

まず、問題を設定します。

data = <<EOF
Place Div/Tot Div   Guntime  PerF 1sthalf 2ndhalf 100m   Name                      Club                       Nettime 
===== ======= ===== =======  ==== ======= ======= ====== ========================= ========================== ======= 
    1   1/24  M3034   24:46   866   12:11   12:35  15.88 Andy Bas                  Prairie Inn Harriers         24:46 
    2   1/47  M4044   25:03*  856   12:22   12:41  17.52 Some Name Yo              Prairie Inn Harriers Runni   25:03 
EOF
lines = data.split "\n"

String#unpackのフォーマット文字列を作成するのが好きです。

format = lines[1].scan(/(=+)(\s+)/).map{|f, s| "A#{f.size}" + 'x' * s.size}.join
#=> A5xA7xA5xA7xxA4xA7xA7xA6xA25xA26xA7x

残りは簡単です:

headers = lines[0].unpack format
lines[2..-1].each do |line|
  puts Hash[headers.zip line.unpack(format).map(&:strip)]
end
#=> {"Place"=>"1", "Div/Tot"=>"1/24", "Div"=>"M3034", "Guntime"=>"24:46", "PerF"=>"866", "1sthalf"=>"12:11", "2ndhalf"=>"12:35", "100m"=>"15.88", "Name"=>"Andy Bas", "Club"=>"Prairie Inn Harriers", "Nettime"=>"24:46"}
#=> {"Place"=>"2", "Div/Tot"=>"1/47", "Div"=>"M4044", "Guntime"=>"25:03", "PerF"=>"856", "1sthalf"=>"12:22", "2ndhalf"=>"12:41", "100m"=>"17.52", "Name"=>"Some Name Yo", "Club"=>"Prairie Inn Harriers Runni", "Nettime"=>"25:03"}
于 2012-10-11T06:54:06.990 に答える
2

これはうまくいくはずです

divider = "===== ======= ===== =======  ==== ======= ======= ====== ========================= ========================== ======="
str     = "    1   1/24  M3034   24:46   866   12:11   12:35  15.88 Andy Bas                  Prairie Inn Harriers         24:46"

divider.split(/\s+/).each {|delimiter| puts str.slice!(0..delimiter.size).strip }
于 2012-10-11T06:24:41.443 に答える
0

これが実用的な解決策です(あなたが与えたファイルに基づいていますが、私が推測するこの形式のすべてのファイルに一般化する必要があります):

#!/usr/bin/env ruby

FILE = 'gistfile1.txt'

f = File.new(FILE,'r')

l = f.gets #read first line (which contains the headers)

#parse for the columns: header text, where they start,stop & len
headers = l.scan(/(\S+\W+)/).each.map{|s| [s.join, l.index(s.join), s.join.length]}.map{|a| {:head=>a[0].strip,:start=>a[1],:end=>a[1]+a[2],:len=>a[2]}}

f.gets #to skip past the header-data separator line

records = []

while( l = f.gets)
    record = {}
    headers.each{|h|
        record[h[:head]] = l[h[:start]...h[:end]].strip
        print "#{h[:head]} => #{record[h[:head]]}\n"
    }   
    print "*" * l.length,"\n"
    records << record
end

#records contains each record, with each column header mapped onto the respective data record

デモでは、次の手順に従ってレコードをエコーし​​ます。

Place => 1
Div/Tot => 1/24
Div => M3034
Guntime => 24:46
PerF => 866
1sthalf => 12:11
2ndhalf => 12:35
100m => 15.88
Name => Andy Bas
Club => Prairie Inn Harriers
Nettime => 24:46
***********************************************************************************************************************
Place => 2
Div/Tot => 1/47
Div => M4044
Guntime => 25:03*
PerF => 856
1sthalf => 12:22
2ndhalf => 12:41
100m => 17.52
Name => Some Name Yo
Club => Prairie Inn Harriers Runni
Nettime => 25:03
**********************************************************************************************************************
于 2012-10-11T07:06:15.757 に答える
0
header, format, *data = plain_text_table.split($/)
h = {}
format.scan(/=+/) do
  range = $~.begin(0)..$~.end(0)
  h[header[range].strip] = data.map{|s| s[range].strip}
end

h # => {
  "Place" => ["1", "2"],
  "Div/Tot" => ["1/24", "1/47"],
  "Div" => ["M3034", "M4044"],
  "Guntime" => ["24:46", "25:03*"],
  "PerF" => ["866", "856"],
  "1sthalf" => ["12:11", "12:22"],
  "2ndhalf" => ["12:35", "12:41"],
  "100m" => ["15.88", "17.52"],
  "Name" => ["Andy Bas", "Some Name Yo"],
  "Club" => ["Prairie Inn Harriers", "Prairie Inn Harriers Runni"],
  "Nettime" => ["24:46", "25:03"]
}
于 2012-10-11T09:28:07.700 に答える