2009-09-06 44 views
0

我必須通過以下文本並匹配以下各項,並將它們拆分爲單獨的記錄以保存到數據庫。所以,這樣的文字:在Ruby中匹配循環中的文本

ESTIMATED MINIMUM CENTRAL PRESSURE 951 MB 
EYE DIAMETER 12 NM 
MAX SUSTAINED WINDS 105 KT WITH GUSTS TO 130 KT 
64 KT....... 25NE 25SE 25SW 25NW 
50 KT....... 60NE 30SE 30SW 60NW 
34 KT....... 75NE 50SE 50SW 75NW 
12 FT SEAS.. 75NE 50SE 50SW 75NW 
ALL QUADRANT RADII IN NAUTICAL MILES 

REPEAT...CENTER LOCATED NEAR 25.5N 73.4W AT 23/0900Z 
AT 23/0600Z CENTER WAS LOCATED NEAR 25.5N 72.6W 

FORECAST VALID 23/1800Z 25.4N 75.6W 
MAX WIND 110 KT...GUSTS 135 KT 
50 KT... 60NE 60SE 60SW 60NW 
34 KT... 75NE 75SE 75SW 75NW 

FORECAST VALID 24/0600Z 25.5N 78.8W 
MAX WIND 115 KT...GUSTS 140 KT 
50 KT... 60NE 60SE 60SW 60NW 
34 KT...100NE 100SE 100SW 100NW 

FORECAST VALID 24/1800Z 25.8N 81.8W 
MAX WIND 85 KT...GUSTS 105 KT 
50 KT... 60NE 60SE 60SW 60NW 
34 KT...100NE 100SE 100SW 100NW 

...應該結束了看起來像以下:

forecastAdvisory = { 
    :centralPressure => 951, 
    :eyeDiameter => 12, 
    :vMax => 105, 
    :gMax => 130, 
    :windRadii => { 
    64 => [25, 25, 25, 25], 
    50 => [60, 30, 30, 60], 
    34 => [75, 50, 50, 75], 
    12 => [75, 50, 50, 75] 
    }, 
    :forecastTrack => { 
    12 => { 
     :latitude => 25.4, 
     :longitude => 75.6, 
     :vMax => 110, 
     :gMax => 135 
     :windRadii => { 
     50 => [60, 60, 60, 60] 
     34 => [75, 75, 75, 75] 
     } 
    }, 
    24 => { 
     :latitude => 25.5, 
     :longitude => 78.8, 
     :vMax => 115, 
     :gMax => 140 
     :windRadii => { 
     50 => [60, 60, 60, 60] 
     34 => [100, 100, 100, 100] 
     } 
    }, 
    36 => { 
     :latitude => 25.8, 
     :longitude => 81.8, 
     :vMax => 85, 
     :gMax => 105 
     :windRadii => { 
     50 => [60, 60, 60, 60] 
     34 => [100, 100, 100, 100] 
     } 
    } 
    } 
} 

我知道我大概可以使用scan方法在Ruby中String,但我不知道關於如何按順序瀏覽文件並獲取這些值並正確解析它們。

UPDATE:這裏是我會用File.open來分析幾個樣本文件,僅供參考:

+0

如果沒有更好地理解問題,就很難提供任何建議,例如,這是一個文件的內容,你有很多文件?所有記錄都在一個文件中,但重複多次。你似乎有5塊數據,是永遠的情況下等 – 2009-09-06 20:28:50

+0

@Steve - 這裏有多個變量,不幸的是: *不同的風半徑是34,50或64 KT。並非所有的風暴都有一定的風力半徑(所以有時風速半徑甚至不會包含在一個文本塊中),有些風速有34個,但不是50和64,等等。 *會有多個文件,但我會一次解析一個(每個諮詢一個) 以下是我將解析的幾個不同文件的示例: * http://is.gd/2XZ3N * http://is.gd/2XZ5N * http://is.gd/2XZ7y – 2009-09-06 20:33:43

回答

1

我張貼的答案,是因爲我覺得答案真的沒有滿足張貼在原來的問題要求。基本上,有與同一起跑線多個文本塊,像這樣:

FORECAST VALID 23/1800Z 25.4N 75.6W 
... 
FORECAST VALID 24/0600Z 25.5N 78.8W 
... 
FORECAST VALID 24/1800Z 25.8N 81.8W 

我最終什麼事做的是創造了該行正則表達式:

/^(FORECAST|OUTLOOK)\sVALID\s(\d+)\/(\d+)Z\s([\d\.]+)N\s+([\d\.]+)W/ 

現在,我需要循環遍歷每一個文本塊,直到沒有剩下的東西。由於這些預測通常是在諮詢結束時做出的,所以我這樣做了:

forecast_data = [] 

# Grab the rest of the forecast data 
until data.eof? 
    forecast_data << data.readline.strip 
end 

forecast_times = [12,24,36,48,72,96,120] 
forecasts ||= {} 
current_forecast = {} 

until forecast_data.empty? 
    line = forecast_data.shift 

    if line =~ regular_expression 
    # Start a new "current_forecast" array, which 
    # contains the current block of text's data, 
    # and parse it... 
    forecasts.merge!(hour => current_forecast) 
    end 

    # Additional parsing for this block here... 
end 

# Merge the final block in with the rest 
forecasts.merge!(hour => current_forecast) unless current_forecast.empty? 

這似乎有效。如果其他人對如何重構這個問題有任何想法,或者使用其他方法做得更好,請隨時添加其他答案或評論,我會改變答案!感謝所有張貼的人;它真正的讚賞。

1

使用此僞碼

File.open("filename") do |l| 
    one,two,three,four,five,six = l.split(" ") 
    three = three[0,1] 
    four = four[0,1] 
    five = five[0,1] 
    six = six[0,1] 
    // code to create output format 
end 

因此,例如,該行:

64 => [25, 25, 25, 25] 

is formed by 
one => [three,four,five,six] 
+0

我在主要問題中增加了一些示例建議。如果它有助於您的回答,請查看這些文件以查看文件中還包含其他內容。它(不幸)不僅僅是我發佈的內容,因爲我發佈的內容只是一個摘錄。 :/ – 2009-09-06 20:40:33

0

如果你想保留它通用的,你可以使用標準輸入,如

forecastparser.rb < forecast.txt 

,並通過

input = $<.read.split 
input.each do |line| 
... 
end 
+0

我認爲它不怎麼介紹如何導入文件,更多關於如何自己解析這些文本塊,瀏覽文件並以某種方式「捕捉」每一個文本(按照它們出現的順序) – 2009-09-06 20:39:38

0
閱讀每一行

爲此建立一個右遞歸語法應該是相當容易的,例如:

forecast : FORECAST VALID <int>/<int>Z <int><direction> <int><direction> \n <maxwind> <forecast_list> 

direction : N 
      | S 
      | E 
      | W 
      | NE 
      | NW (etc etc) 

maxwind : MAX WIND <int> KT...GUSTS <int> KT 

forecast_list : forecast_line \n forecast_list 
       | 

forecast_line : <int> KT... <int><direction> <int><direction> <int><direction> <int><direction> 

用這樣的語法,你可以寫(遞人)遞歸下降解析器,這應該很簡單。這樣做的好處是您的生產規則無上下文,所以您應該能夠相當容易地處理小格式轉換或新類型的數據文件。

0

快速瀏覽一下鏈接的文件,即使格式差別很大,文件之間的信息「塊」似乎是相同的 - 相同類型的信息 - 即使格式大不相同?

所以,如果我要這樣做,我會得到每個塊的可能值的列表,然後測試/解析每個塊。如果這是一個颶風警告,我知道沒有任何重要的數字,但熱帶低氣壓可能有我感興趣的東西。(在一個側面說明一個熱帶消沉聽起來真的很有趣,我作爲一個瑞典人沒有聽說過任何天氣被稱爲正式鬱悶^^)

 

@block_no = 0 
[..] 
File.open('forecast') do |f| 
    block = [] 
    line = file.readline.strip 
    block << line unless line.strip == '' 

    Forecast.parse(block) # which has the current block_no and knows what kind of possible values there are to read out 
    @block_no += 1 
end 
 

這種感覺是一個非常通用的答案,但如果我嘗試這樣做,我需要知道的所有可能的格式信息可以在我之前可以顯示出來拿出一個好的解決方案。可能只是使用一大堆String#掃描調用將是最好的。:)

好運