lib/eew_parser.rb in eew_parser-0.1.3 vs lib/eew_parser.rb in eew_parser-0.1.4

- old
+ new

@@ -574,16 +574,71 @@ 803 => "沖縄県大東島", 804 => "沖縄県宮古島", 805 => "沖縄県石垣島", 806 => "沖縄県与那国島", 807 => "沖縄県西表島"} + + class Error < StandardError; end # 引数には緊急地震速報の電文を与えます。 def initialize(str) @fastcast = str + @fastcast.freeze + raise Error, "電文の形式が不正です" if @fastcast.size < 134 end + attr_reader :fastcast + + # initializeに与えられた電文を返します。 + def to_s + @fastcast + end + + # 電文を解析した結果をHashで返します。 + def to_hash + hash = {} + hash[:type] = self.type + hash[:from] = self.from + hash[:drill_type] = self.drill_type + hash[:report_time] = self.report_time + hash[:number_of_telegram] = self.number_of_telegram + hash[:continue?] = self.continue? + hash[:earthquake_time] = self.earthquake_time + hash[:id] = self.id + hash[:status] = self.status + hash[:final?] = self.final? + hash[:number] = self.number + hash[:epicenter] = self.epicenter + hash[:position] = self.position + hash[:depth] = self.depth + hash[:magnitude] = self.magnitude + hash[:seismic_intensity] = self.seismic_intensity + hash[:probability_of_position] = self.probability_of_position + hash[:probability_of_depth] = self.probability_of_depth + hash[:probability_of_magnitude] = self.probability_of_magnitude + hash[:probability_of_position_jma] = self.probability_of_position_jma + hash[:probability_of_depth_jma] = self.probability_of_depth_jma + hash[:land_or_sea] = self.land_or_sea + hash[:warning?] = self.warning? + hash[:change] = self.change + hash[:reason_of_change] = self.reason_of_change + hash[:ebi] = self.ebi + hash + end + + def inspect + "#<EEWParser:#{self.id}>" + end + + def ==(other) + self.fastcast == other.fastcast + end + + def <=>(other) + self.id.to_i <=> other.id.to_i + end + # 電文種別コード def type case @fastcast[0, 2] when "35" "最大予測震度のみの高度利用者向け緊急地震速報" @@ -591,10 +646,12 @@ "マグニチュード、最大予測震度及び主要動到達予測時刻の高度利用者向け緊急地震速報(B-Δ法、テリトリ法)" when "37" "マグニチュード、最大予測震度及び主要動到達予測時刻の高度利用者向け緊急地震速報(グリッドサーチ法、EPOS自動処理手法)" when "39" "キャンセル報" + else + raise Error, "電文の形式が不正です(電文種別コード)" end end # 発信官署 def from @@ -609,10 +666,12 @@ "大阪" when "05" "福岡" when "06" "沖縄" + else + raise Error, "電文の形式が不正です(発信官署)" end end # 訓練等の識別符 def drill_type @@ -627,36 +686,49 @@ "訓練取り消し" when "20" "参考情報またはテキスト" when "30" "コード部のみの配信試験" + else + raise Error, "電文の形式が不正です(識別符)" end end # 電文の発表時刻のTimeオブジェクトを返します。 def report_time Time.local("20" + @fastcast[9, 2], @fastcast[11, 2], @fastcast[13, 2], @fastcast[15, 2], @fastcast[17, 2], @fastcast[19, 2]) end # 電文がこの電文を含め何通あるか(Integer) def number_of_telegram - @fastcast[23].to_i + number_of_telegram = @fastcast[23] + raise Error, "電文の形式が不正です" if number_of_telegram =~ /[^\d]/ + number_of_telegram.to_i end # コードが続くかどうか def continue? - @fastcast[24] == "1" + case @fastcast[24] + when "1" + true + when "0" + false + else + raise Error, "電文の形式が不正です" + end end # 地震発生時刻もしくは地震検知時刻のTimeオブジェクトを返します。 def earthquake_time Time.local("20" + @fastcast[26, 2], @fastcast[28, 2], @fastcast[30, 2], @fastcast[32, 2], @fastcast[34, 2], @fastcast[36, 2]) end # 地震識別番号(String) def id - @fastcast[41, 14] + id = @fastcast[41, 14] + raise Error, "電文の形式が不正です(地震識別番号)" if id =~ /[^\d]/ + id end # 発表状況(訂正等)の指示 def status case @fastcast[59] @@ -670,57 +742,75 @@ "訂正事項を盛り込んだ最終の高度利用者向け緊急地震速報" when "9" "最終の高度利用者向け緊急地震速報" when "/" "未設定" + else + raise Error, "電文の形式が不正です" end end # 最終報であればtrueを、そうでなければfalseを返します。 def final? - @fastcast[59] == "9" + case @fastcast[59] + when "9" + true + when "0", "6", "7", "8", "/" + false + else + raise Error, "電文の形式が不正です" + end end # 発表する高度利用者向け緊急地震速報の番号(地震単位での通番)(Integer) def number - @fastcast[60, 2].to_i + number = @fastcast[60, 2] + raise Error, "電文の形式が不正です(高度利用者向け緊急地震速報の番号)" if number =~ /[^\d]/ + number.to_i end alias :revision :number # 震央の名称 def epicenter - EpicenterCord[@fastcast[86, 3].to_i] + key = @fastcast[86, 3] + raise Error, "電文の形式が不正です(震央の名称)" if key =~ /[^\d]/ + EpicenterCord[key.to_i] end # 震央の位置 def position position = @fastcast[90, 10] if position == "//// /////" "不明又は未設定" else + raise Error, "電文の形式が不正です(震央の位置)" if position =~ /[^\d|\s|N|E]/ position.insert(3, ".").insert(10, ".") end end # 震源の深さ(単位 km) def depth - if @fastcast[101, 3] == "///" + depth = @fastcast[101, 3] + if depth == "///" "不明又は未設定" else - @fastcast[101, 3].to_i + raise Error, "電文の形式が不正です(震源の深さ)" if depth =~ /[^\d]/ + depth.to_i end end # マグニチュード # マグニチュードが不明又は未設定である場合は"不明又は未設定"を返します。 # そうでなければ、マグニチュードをFloatで返します。 def magnitude - if @fastcast[105, 2] == "//" + magnitude = @fastcast[105, 2] + if magnitude == "//" "不明又は未設定" else - (@fastcast[105] + "." + @fastcast[106]).to_f + raise Error, "電文の形式が不正です(マグニチュード)" if magnitude =~ /[^\d]/ + (magnitude[0] + "." + magnitude[1]).to_f end end # 電文フォーマットの震度を文字列に変換 def to_seismic_intensity(str) @@ -743,16 +833,20 @@ "6弱" when "6+" "6強" when "07" "7" + else + raise Error, "電文の形式が不正です(震度)" end end # 最大予測震度 def seismic_intensity to_seismic_intensity(@fastcast[108, 2]) + rescue Error + raise Error, "電文の形式が不正です(最大予測震度)" end # 震央の確からしさ def probability_of_position case @fastcast[113] @@ -774,10 +868,12 @@ "EPOS(内陸[観測網内])[気象庁データ]" when "9" "予備" when "/" "不明又は未設定" + else + raise Error, "電文の形式が不正です(震央の確からしさ)" end end # 震源の深さの確からしさ def probability_of_depth @@ -800,10 +896,12 @@ "EPOS(内陸[観測網内])[気象庁データ]" when "9" "予備" when "/" "不明又は未設定" + else + raise Error, "電文の形式が不正です(震源の深さの確からしさ)" end end # マグニチュードの確からしさ def probability_of_magnitude @@ -826,10 +924,12 @@ "P波/S波レベル越え[気象庁データ]" when "9" "予備" when "/" "不明又は未設定" + else + raise Error, "電文の形式が不正です(マグニチュードの確からしさ)" end end # 震央の確からしさ(※気象庁の部内システムでの利用) def probability_of_position_jma @@ -842,12 +942,14 @@ "グリッドサーチ法(3点/4点)[気象庁データ]" when "4" "グリッドサーチ法(5点)[気象庁データ]" when "/" "不明又は未設定" - else + when "5".."9" "未定義" + else + raise Error, "電文の形式が不正です(震央の確からしさ[気象庁の部内システムでの利用])" end end # 震源の深さの確からしさ(※気象庁の部内システムでの利用) def probability_of_depth_jma @@ -860,12 +962,14 @@ "グリッドサーチ法(3点/4点)[気象庁データ]" when "4" "グリッドサーチ法(5点)[気象庁データ]" when "/" "不明又は未設定" - else + when "5".."9" "未定義" + else + raise Error, "電文の形式が不正です(震源の深さの確からしさ[気象庁の部内システムでの利用])" end end # 震央位置の海陸判定 def land_or_sea @@ -874,18 +978,27 @@ "陸域" when "1" "海域" when "/" "不明又は未設定" - else + when "2".."9" "未定義" + else + raise Error, "電文の形式が不正です(震央位置の海陸判定)" end end # 警報を含む内容であればtrue、そうでなければfalse def warning? - @fastcast[122] == "1" + case @fastcast[122] + when "0", "/", "2".."9" + false + when "1" + true + else + raise Error, "電文の形式が不正です(警報の判別)" + end end # 最大予測震度の変化 def change case @fastcast[129] @@ -893,12 +1006,16 @@ "ほとんど変化無し" when "1" "最大予測震度が1.0以上大きくなった" when "2" "最大予測震度が1.0以上小さくなった" - else + when "3".."9" "未定義" + when "/" + "不明又は未設定" + else + raise Error, "電文の形式が不正です(最大予測震度の変化)" end end # 最大予測震度の変化の理由 def reason_of_change @@ -913,17 +1030,19 @@ "M及び震源位置が変化したため" when "4" "震源の深さが変化したため" when "/" "不明又は未設定" - else + when "5".."9" "未定義" + else + raise Error, "電文の形式が不正です(最大予測震度の変化の理由)" end end # 地域毎の警報の判別、最大予測震度及び主要動到達予測時刻 - # EBIがあればHashを格納したArrayを、なければnilを返します。Hashに格納されるkeyとvalueはそれぞれ次のようになっています。 + # EBIがあればHashを格納したArrayを、なければ空のArrayを返します。Hashに格納されるkeyとvalueはそれぞれ次のようになっています。 # :area_name 地域名称 # :intensity 最大予測震度 # :arrival_time 予想到達時刻のTimeオブジェクト。既に到達している場合はnil # :warning 警報を含んでいればtrue、含んでいなければfalse、電文にこの項目が設定されていなければnil # :arrival 既に到達していればtrue、そうでなければfalse、電文にこの項目が設定されていなければnil @@ -932,10 +1051,11 @@ return data unless @fastcast[135, 3] == "EBI" i = 139 while i + 20 < @fastcast.size local = {} local[:area_name] = AreaCord[@fastcast[i, 3].to_i] # 地域名称 + raise Error, "電文の形式が不正でです(地域名称[EBI])" unless local[:area_name] if @fastcast[i+7, 2] == "//" local[:intensity] = "#{to_seismic_intensity(@fastcast[i+5, 2])}以上" # 最大予測震度 elsif @fastcast[i+5, 2] == @fastcast[i+7, 2] local[:intensity] = "#{to_seismic_intensity(@fastcast[i+5, 2])}" else @@ -949,30 +1069,34 @@ case @fastcast[i+17] when "0" local[:warning] = false # 警報を含むかどうか when "1" local[:warning] = true - else + when "/", "2".."9" local[:warning] = nil + else + raise Error, "電文の形式が不正でです(警報の判別[EBI])" end case @fastcast[i+18] when "0" local[:arrival] = false # 既に到達しているかどうか when "1" local[:arrival] = true - else + when "/", "2".."9" local[:arrival] = nil + else + raise Error, "電文の形式が不正でです(主要動の到達予測状況[EBI])" end data << local i += 20 end data end end if __FILE__ == $PROGRAM_NAME # テスト -str = <<EOS #テスト用の電文 + str = <<EOS #テスト用の電文 37 03 00 110415233453 C11 110415233416 ND20110415233435 NCN005 JD////////////// JN/// 251 N370 E1408 010 66 6+ RK66324 RT01/// RC13/// EBI 251 S6+6- ////// 11 300 S5+5- ////// 11 250 S5+5- ////// 11 @@ -981,14 +1105,17 @@ 341 S0404 ////// 01 321 S0404 233455 00 331 S0404 233457 10 350 S0404 233501 00 360 S0404 233508 00 243 S0403 ////// 01 330 S0403 233454 00 222 S0403 233455 00 9999= EOS -p str -fc = EEWParser.new(str) - -puts <<FC + + fc = EEWParser.new(str) + p fc + p fc.fastcast + p fc.to_hash + + puts <<FC 電文種別コード: #{fc.type} 発信官署: #{fc.from} 訓練等の識別符: #{fc.drill_type} 電文の発表時刻: #{fc.report_time} 電文がこの電文を含め何通あるか: #{fc.number_of_telegram} @@ -1008,12 +1135,12 @@ 震央の確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_position_jma} 震源の深さの確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_depth_jma} 震央位置の海陸判定: #{fc.land_or_sea} 警報を含む内容かどうか: #{fc.warning?} 最大予測震度の変化: #{fc.change} -最大予測震度の変化の理由: #{fc.reason_of_chaage} +最大予測震度の変化の理由: #{fc.reason_of_change} FC -fc.ebi.each do |local| - puts "地域コード: #{local[:area_cord]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{local[:arrival_time]}" - puts "警報を含むかどうか: #{local[:warning]} 既に到達しているかどうか: #{local[:arrival]}" -end + fc.ebi.each do |local| + puts "地域コード: #{local[:area_cord]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{local[:arrival_time]}" + puts "警報を含むかどうか: #{local[:warning]} 既に到達しているかどうか: #{local[:arrival]}" + end end