lib/eew_parser.rb in eew_parser-0.1.7 vs lib/eew_parser.rb in eew_parser-0.1.8

- old
+ new

@@ -44,45 +44,50 @@ @fastcast.bytesize end # 緊急地震速報の内容をテキストで出力します。 def print - str = <<-EOS -電文種別: #{self.type} -発信官署: #{self.from} -訓練等の識別符: #{self.drill_type} -電文の発表時刻: #{self.report_time} -電文がこの電文を含め何通あるか: #{self.number_of_telegram} -コードが続くかどうか: #{self.continue?} -地震発生時刻もしくは地震検知時刻: #{self.earthquake_time} -地震識別番号: #{self.id} -発表状況(訂正等)の指示: #{self.status} -発表する高度利用者向け緊急地震速報の番号(地震単位での通番): #{self.number} -震央地名: #{self.epicenter} -震央の位置: #{self.position} -震源の深さ(単位 km)(不明・未設定時,キャンセル時:///): #{self.depth} -マグニチュード(不明・未設定時、キャンセル時:///): #{self.magnitude} -最大予測震度(不明・未設定時、キャンセル時://): #{self.seismic_intensity} -震央の確からしさ: #{self.probability_of_position} -震源の深さの確からしさ: #{self.probability_of_depth} -マグニチュードの確からしさ: #{self.probability_of_magnitude} -震央の確からしさ(気象庁の部内システムでの利用): #{self.probability_of_position_jma} -震源の深さの確からしさ(気象庁の部内システムでの利用): #{self.probability_of_depth_jma} -震央位置の海陸判定: #{self.land_or_sea} -警報を含む内容かどうか: #{self.warning?} -最大予測震度の変化: #{self.change} -最大予測震度の変化の理由: #{self.reason_of_change} + return @print.dup if @print + + @print = <<-EOS +緊急地震速報 (第#{number}報) +電文種別: #{type} +発信官署: #{from} +訓練等の識別符: #{drill_type} +電文の発表時刻: #{report_time.strftime("%F %T")} +電文がこの電文を含め何通あるか: #{number_of_telegram} +コードが続くかどうか: #{continue?} +地震発生時刻もしくは地震検知時刻: #{earthquake_time.strftime("%F %T")} +地震識別番号: #{id} +発表状況(訂正等)の指示: #{status} +発表する高度利用者向け緊急地震速報の番号(地震単位での通番): #{number} +震央地名: #{epicenter} +震央の位置: #{position} +震源の深さ(単位 km)(不明・未設定時,キャンセル時:///): #{depth} +マグニチュード(不明・未設定時、キャンセル時:///): #{magnitude} +最大予測震度(不明・未設定時、キャンセル時://): #{seismic_intensity} +震央の確からしさ: #{probability_of_position} +震源の深さの確からしさ: #{probability_of_depth} +マグニチュードの確からしさ: #{probability_of_magnitude} +震央の確からしさ(気象庁の部内システムでの利用): #{probability_of_position_jma} +震源の深さの確からしさ(気象庁の部内システムでの利用): #{probability_of_depth_jma} +震央位置の海陸判定: #{land_or_sea} +警報を含む内容かどうか: #{warning?} +最大予測震度の変化: #{change} +最大予測震度の変化の理由: #{reason_of_change} EOS - unless self.ebi.empty? - str << "\n地域毎の警報の判別、最大予測震度及び主要動到達予測時刻(EBI):" - self.ebi.each do |local| - str << "地域名: #{local[:area_name]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{local[:arrival_time]} 警報を含むかどうか: #{local[:warning]} 既に到達しているかどうか: #{local[:arrival]}\n" + if has_ebi? + @print << "\n地域毎の警報の判別、最大予測震度及び主要動到達予測時刻(EBI):\n" + ebi.each do |local| + arrival_time = local[:arrival] ? "すでに到達" : local[:arrival_time]&.strftime("%T") + @print << "#{local[:area_name]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{arrival_time} 警報: #{local[:warning]}\n" end end - return str + @print.freeze + return @print.dup end Attributes = [ :type, :from, :drill_type, :report_time, :number_of_telegram, :continue?, :earthquake_time, :id, :status, :final?, :number, :epicenter, :position, :depth, :magnitude, :seismic_intensity, :probability_of_position_jma, :probability_of_depth, :probability_of_magnitude, :probability_of_position, :probability_of_depth_jma, @@ -105,11 +110,11 @@ end return true end def inspect - "#<EEWParser:#{id} (第#{number}報) #{epicenter} #{seismic_intensity}>" + "#<EEWParser:#{id} (第#{number}報) #{epicenter} 震度#{seismic_intensity}>" end def ==(other) fastcast == other.fastcast end @@ -187,10 +192,12 @@ 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]) + rescue ArgumentError + raise Error, "電文の形式が不正です (発表時刻: #{@fastcast[9, 12]})" end # 電文がこの電文を含め何通あるか(Integer) def number_of_telegram number_of_telegram = @fastcast[23] @@ -212,10 +219,12 @@ 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]) + rescue ArgumentError + raise Error, "電文の形式が不正です (地震発生時刻: #{@fastcast[26, 12]})" end # 地震識別番号(String) def id id = @fastcast[41, 14] @@ -224,11 +233,11 @@ rescue ArgumentError raise Error, "電文の形式が不正です(地震識別番号: #{id})" end def __id__ - id + number.to_s + (id * 10) + number end # 発表状況(訂正等)の指示 def status case @fastcast[59] @@ -247,10 +256,16 @@ else raise Error, "電文の形式が不正です" end end + # 発表状況と訓練識別が通常かどうか + def normal? + return true if @fastcast[59] == "0" && @fastcast[6, 2] == "00" + return false + end + # 第1報であればtrueを、そうでなければfalseを返します。 def first? return true if self.number == 1 return false end @@ -270,33 +285,31 @@ # 発表する高度利用者向け緊急地震速報の番号(地震単位での通番)(Integer) def number number = @fastcast[60, 2] return Integer(number, 10) rescue ArgumentError - raise Error, "電文の形式が不正です(高度利用者向け緊急地震速報の番号)" + raise Error, "電文の形式が不正です(高度利用者向け緊急地震速報の番号: #{number})" end alias :revision :number # 震央の名称 def epicenter code = @fastcast[86, 3] code = Integer(code, 10) EpicenterCode.fetch(code) - rescue KeyError + rescue ArgumentError, KeyError raise Error, "電文の形式が不正です(震央地名コード: #{code})" - rescue ArgumentError - raise Error, "電文の形式が不正です(震央の名称)" end # 震央の位置 def position position = @fastcast[90, 10] if position == "//// /////" "不明又は未設定" else - raise Error, "電文の形式が不正です(震央の位置)" unless position.match(/N\d{3} E\d{4}/) + raise Error, "電文の形式が不正です(震央の位置)" unless position.match(/(?:N|S)\d{3} (?:E|W)\d{4}/) position.insert(3, ".").insert(10, ".") end end # 震源の深さ(単位 km) @@ -323,161 +336,131 @@ end rescue ArgumentError raise Error, "電文の形式が不正です(マグニチュード)" end + SeismicIntensity = { + "//" => "不明又は未設定", + "01" => "1", + "02" => "2", + "03" => "3", + "04" => "4", + "5-" => "5弱", + "5+" => "5強", + "6-" => "6弱", + "6+" => "6強", + "07" => "7" + }.freeze + # 電文フォーマットの震度を文字列に変換 def to_seismic_intensity(str) - case str - when "//" - "不明又は未設定" - when "01" - "1" - when "02" - "2" - when "03" - "3" - when "04" - "4" - when "5-" - "5弱" - when "5+" - "5強" - when "6-" - "6弱" - when "6+" - "6強" - when "07" - "7" - else - raise Error, "電文の形式が不正です(震度)" - end + SeismicIntensity.fetch(str) + rescue KeyError + raise Error, "電文の形式が不正です(震度: #{str})" end # 最大予測震度 def seismic_intensity to_seismic_intensity(@fastcast[108, 2]) end + OriginProbability = { + "1" => "P波/S波レベル越え、またはIPF法(1点) または仮定震源要素の場合", + "2" => "IPF法(2点)", + "3" => "IPF法(3点/4点)", + "4" => "IPF法(5点)", + "5" => "防災科研システム(4点以下、または精度情報なし)[防災科研Hi-netデータ]", + "6" => "防災科研システム(5点以上)[防災科研Hi-netデータ]", + "7" => "EPOS(海域[観測網外])", + "8" => "EPOS(内陸[観測網内])", + "9" => "予備", + "/" =>"不明又は未設定" + }.freeze + # 震央の確からしさ def probability_of_position - case @fastcast[113] - when "1" - "P波/S波レベル越え、またはテリトリー法(1点)[気象庁データ]" - when "2" - "テリトリー法(2点)[気象庁データ]" - when "3" - "グリッドサーチ法(3点/4点)[気象庁データ]" - when "4" - "グリッドサーチ法(5点)[気象庁データ]" - when "5" - "防災科研システム(4点以下、または精度情報なし)[防災科学技術研究所データ]" - when "6" - "防災科研システム(5点以上)[防災科学技術研究所データ]" - when "7" - "EPOS(海域[観測網外])[気象庁データ]" - when "8" - "EPOS(内陸[観測網内])[気象庁データ]" - when "9" - "予備" - when "/" - "不明又は未設定" - else - raise Error, "電文の形式が不正です(震央の確からしさ)" - end + OriginProbability.fetch(@fastcast[113]) + rescue KeyError + raise Error, "電文の形式が不正です(震央の確からしさ)" end # 震源の深さの確からしさ def probability_of_depth - case @fastcast[114] - when "1" - "P波/S波レベル越え、またはテリトリー法(1点)[気象庁データ]" - when "2" - "テリトリー法(2点)[気象庁データ]" - when "3" - "グリッドサーチ法(3点/4点)[気象庁データ]" - when "4" - "グリッドサーチ法(5点)[気象庁データ]" - when "5" - "防災科研システム(4点以下、または精度情報なし)[防災科学技術研究所データ]" - when "6" - "防災科研システム(5点以上)[防災科学技術研究所データ]" - when "7" - "EPOS(海域[観測網外])[気象庁データ]" - when "8" - "EPOS(内陸[観測網内])[気象庁データ]" - when "9" - "予備" - when "/", "0" - "不明又は未設定" - else - raise Error, "電文の形式が不正です(震源の深さの確からしさ)" - end + OriginProbability.fetch(@fastcast[114]) + rescue KeyError + raise Error, "電文の形式が不正です(震央の確からしさ)" end # マグニチュードの確からしさ def probability_of_magnitude case @fastcast[115] when "1" "未定義" when "2" - "防災科研システム[防災科学技術研究所データ]" + "防災科研システム[防災科研Hi-netデータ]" when "3" - "全点P相(最大5点)[気象庁データ]" + "全点P相" when "4" - "P相/全相混在[気象庁データ]" + "P相/全相混在" when "5" - "全点全相(最大5点)[気象庁データ]" + "全点全相" when "6" - "EPOS[気象庁データ]" + "EPOS" when "7" "未定義" when "8" - "P波/S波レベル越え[気象庁データ]" + "P波/S波レベル越え または仮定震源要素の場合" when "9" "予備" when "/", "0" "不明又は未設定" else raise Error, "電文の形式が不正です(マグニチュードの確からしさ)" end end - # 震央の確からしさ(※気象庁の部内システムでの利用) - def probability_of_position_jma + # マグニチュード使用観測点(※気象庁の部内システムでの利用) + def observation_points_of_magnitude case @fastcast[116] when "1" - "P波/S波レベル越え又はテリトリー法(1点)[気象庁データ]" + "1点、P波/S波レベル超え、または仮定震源要素" when "2" - "テリトリー法(2点)[気象庁データ]" + "2点" when "3" - "グリッドサーチ法(3点/4点)[気象庁データ]" + "3点" when "4" - "グリッドサーチ法(5点)[気象庁データ]" + "4点" + when "5" + "5点以上" when "/" "不明又は未設定" - when "5".."9", "0" + when "6".."9", "0" "未定義" else - raise Error, "電文の形式が不正です(震央の確からしさ[気象庁の部内システムでの利用])" + raise Error, "電文の形式が不正です(マグニチュード使用観測点[気象庁の部内システムでの利用])" end end + # 後方互換性のため + alias probability_of_position_jma observation_points_of_magnitude + # 震源の深さの確からしさ(※気象庁の部内システムでの利用) def probability_of_depth_jma case @fastcast[117] when "1" - "P波/S波レベル越え又はテリトリー法(1点)[気象庁データ]" + "P波/S波レベル越え、IPF法(1点)、または仮定震源要素" when "2" - "テリトリー法(2点)[気象庁データ]" + "IPF法(2点)" when "3" - "グリッドサーチ法(3点/4点)[気象庁データ]" + "IPF法(3点/4点)" when "4" - "グリッドサーチ法(5点)[気象庁データ]" + "IPF法(5点以上)" + when "9" + "震源とマグニチュードに基づく震度予測手法の精度が最終報相当" when "/" "不明又は未設定" - when "5".."9", "0" + when "5".."8", "0" "未定義" else raise Error, "電文の形式が不正です(震源の深さの確からしさ[気象庁の部内システムでの利用])" end end @@ -508,10 +491,24 @@ else raise Error, "電文の形式が不正です(警報の判別)" end end + # 予測手法 + def warning? + case @fastcast[123] + when "9" + "震源とマグニチュードによる震度推定手法において震源要素が推定できず、PLUM 法による震度予測のみが有効である場合" + when "0".."8" + "未定義" + when "/" + "不明又は未設定" + else + raise Error, "電文の形式が不正です(警報の判別)" + end + end + # 最大予測震度の変化 def change case @fastcast[129] when "0" "ほとんど変化無し" @@ -549,13 +546,15 @@ "主として震源位置が変化したため(10.0km以上)" when "3" "M及び震源位置が変化したため" when "4" "震源の深さが変化したため" + when "9" + "PLUM 法による予測により変化したため" when "/" "不明又は未設定" - when "5".."9" + when "5".."8" "未定義" else raise Error, "電文の形式が不正です(最大予測震度の変化の理由)" end end @@ -575,12 +574,14 @@ # :intensity 最大予測震度 # :arrival_time 予想到達時刻のTimeオブジェクト。既に到達している場合はnil # :warning 警報を含んでいればtrue、含んでいなければfalse、電文にこの項目が設定されていなければnil # :arrival 既に到達していればtrue、そうでなければfalse、電文にこの項目が設定されていなければnil def ebi - data = [] - return data unless @fastcast[135, 3] == "EBI" + return [] unless has_ebi? + return @ebi.dup if @ebi + + @ebi = [] i = 139 while i + 20 < @fastcast.bytesize local = {} local[:area_code] = @fastcast[i, 3].to_i local[:area_name] = AreaCode[local[:area_code]] # 地域名称 @@ -615,14 +616,15 @@ when "/", "2".."9" local[:arrival] = nil else raise Error, "電文の形式が不正でです(主要動の到達予測状況[EBI])" end - data << local + @ebi << local i += 20 end - data + @ebi.freeze + return @ebi.dup end end end EEWParser = EEW::Parser @@ -675,6 +677,9 @@ FC fc.ebi.each do |local| puts "地域コード: #{local[:area_code]} 地域名: #{local[:area_name]} 最大予測震度: #{local[:intensity]} 予想到達時刻: #{local[:arrival_time]}" puts "警報を含むかどうか: #{local[:warning]} 既に到達しているかどうか: #{local[:arrival]}" end + + puts fc.print + p EEW::AreaCode.values.max_by(&:size).size end