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

匹配Ruby循环中的文本

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

    我必须浏览下面的文本并匹配下面的每一个文本,然后将它们分成单独的记录,保存到数据库中。所以本文:

    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 回复  |  直到 13 年前
        1
  •  1
  •   ennuikiller    15 年前

    使用此伪代码

    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    15 年前

    我之所以发布此问题的答案,是因为我觉得这些答案确实不符合原始问题中发布的要求。基本上,有多个文本块具有相同的起始行,因此:

    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    15 年前

    如果你想保持它的通用性,你可以使用stdin,例如

    forecastparser.rb < forecast.txt
    

    通过阅读每一行

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

    应该很容易为此构建正确的递归语法,例如:

    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    15 年前

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

    因此,如果我这样做,我将得到每个块的可能值列表,然后测试/分析其中的每个块。如果这是一个飓风警报,我知道没有任何重要的数字,但是热带低压可能有我感兴趣的东西。(另一方面,作为一个瑞典人,没有听说过任何被官方称为“抑郁”的天气,我觉得热带抑郁症听起来很有趣^ ^)

    
    @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
    
    

    这似乎是一个非常一般的答案,但如果我尝试这样做,我需要知道所有可能的格式,信息可能会出现在之前,我可以想出一个好的解决方案。使用一整串串扫描调用可能是最好的。:)

    祝你好运