代码之家  ›  专栏  ›  技术社区  ›  Josh Delsman

在Ruby中匹配循环中的文本

  •  0
  • Josh Delsman  · 技术社区  · 16 年前

    我必须浏览以下文本并匹配以下每一项,然后将它们分解为单独的记录以保存到数据库中。因此,本文:

    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 方法 String 在Ruby中,但我不确定如何按顺序浏览文件,获取这些值并正确解析它们。

    File.open

    5 回复  |  直到 14 年前
        1
  •  1
  •   ennuikiller    16 年前

    使用此伪代码

    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]
    
        2
  •  1
  •   Josh Delsman    16 年前

    我发布了一个答案,因为我觉得这些答案真的不符合原始问题中发布的要求。基本上,有多个文本块具有相同的起始行,如下所示:

    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?
    

    这似乎奏效了。如果其他人对如何重构这个有任何想法,或者使用另一种方法做得更好,请随时添加另一个答案或评论,我会更改答案!感谢所有发帖的人;它真的很感激。

        3
  •  0
  •   Omar Qureshi    16 年前

    如果你想保持通用性,你可以使用STDIN,例如

    forecastparser.rb < forecast.txt
    

    并通过以下方式读取每一行

    input = $<.read.split
    input.each do |line|
    ...
    end
    
        4
  •  0
  •   Gian Perrone    16 年前

    为此构建一个正确的递归语法应该相当容易,例如:

    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>
    

    有了这样的语法,你可以(手工)编写一个递归下降解析器,这应该很简单。这样做的好处是,您的生产规则是上下文无关的,因此您应该能够相当容易地处理微小的格式转换或新型数据文件。

        5
  •  0
  •   gaqzi    16 年前

    快速浏览一下你链接的那些文件,即使格式大不相同,文件之间的信息“块”似乎也是相同的——相同类型的信息?

    
    @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#scan调用将是最好的。 :)

    祝你好运

    推荐文章