lib/eew_parser.rb in eew_parser-0.2.0 vs lib/eew_parser.rb in eew_parser-0.2.1

- old
+ new

@@ -1,7 +1,9 @@ # encoding: utf-8 +require "time" + require_relative "epicenter_code" require_relative "area_code" # 緊急地震速報パーサ # Author:: mmasaki @@ -28,116 +30,45 @@ def initialize(str) raise ArgumentError unless str.is_a?(String) @fastcast = str.dup @fastcast.force_encoding(Encoding::ASCII) @fastcast.freeze - raise Error, "電文の形式が不正です" if @fastcast.bytesize < 135 + raise Error, "電文のサイズが不正です" if @fastcast.bytesize < 135 end attr_reader :fastcast - # initializeに与えられた電文を返します。 - def to_s - @fastcast.dup + def inspect + "#<EEWParser:#{id} (第#{number}報) #{epicenter} 震度#{seismic_intensity}>" end - # 電文のサイズを返します。 - def size - @fastcast.bytesize + def ==(other) + @fastcast == other.fastcast end - # 緊急地震速報の内容をテキストで出力します。 - def print - 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?} -予測手法: #{prediction_method} -最大予測震度の変化: #{change} -最大予測震度の変化の理由: #{reason_of_change} - EOS - - 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 - - @print.freeze - return @print.dup + def <=>(other) + id + number <=> other.id + other.number end - Attributes = [ - :type, :from, :drill_type, :report_time, :number_of_telegram, :continue?, :earthquake_time, :id, :status, :final?, :number, :epicenter, :position, :depth, - :magnitude, :seismic_intensity, :observation_points_of_magnitude, :probability_of_depth, :probability_of_magnitude, :probability_of_position, :probability_of_depth_jma, - :land_or_sea, :warning?, :prediction_method, :change, :reason_of_change, :ebi - ].freeze - - # 電文を解析した結果をHashで返します。 - def to_hash - unless @hash - @hash = {} - Attributes.each do |attribute| - @hash[attribute] = __send__(attribute) - end - @hash.freeze - end - return @hash.dup + def eql?(other) + @fastcast.eql?(other.fastcast) end - # 正しい電文であるかを返します - def valid? - unless @valid - begin - Attributes.each do |attribute| - __send__(attribute) - end - rescue Error - @valid = false - else - @valid = true - end - end - return @valid + def hash + @fastcast.hash end - def inspect - "#<EEWParser:#{id} (第#{number}報) #{epicenter} 震度#{seismic_intensity}>" + # initializeに与えられた電文を返します。 + def to_s + @fastcast.dup end - def ==(other) - fastcast == other.fastcast + # 電文のサイズを返します。 + def size + @fastcast.bytesize end - def <=>(other) - __id__ <=> other.__id__ - end - # 電文種別コード def type case @fastcast[0, 2] when "35" "最大予測震度のみの高度利用者向け緊急地震速報" @@ -210,11 +141,11 @@ 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]) + Time.strptime(@fastcast[9, 12], "%y%m%d%H%M%S") rescue ArgumentError raise Error, "電文の形式が不正です (発表時刻: #{@fastcast[9, 12]})" end # 電文がこの電文を含め何通あるか(Integer) @@ -237,29 +168,25 @@ 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]) + Time.strptime(@fastcast[26, 12], "%y%m%d%H%M%S") rescue ArgumentError raise Error, "電文の形式が不正です (地震発生時刻: #{@fastcast[26, 12]})" end # 地震識別番号(String) def id - id = @fastcast[41, 14] - Integer(id, 10) # verify - return id + return @id if @id + @id = @fastcast[41, 14] + Integer(@id, 10) # verify + return @id rescue ArgumentError raise Error, "電文の形式が不正です(地震識別番号: #{id})" end - # 地震識別番号 + 通番 - def __id__ - (id * 10) + number - end - # 発表状況(訂正等)の指示 def status case @fastcast[59] when "0" "通常発表" @@ -368,10 +295,11 @@ "5+" => "5強", "6-" => "6弱", "6+" => "6強", "07" => "7" }.freeze + private_constant :SeismicIntensity # 最大予測震度 def seismic_intensity to_seismic_intensity(@fastcast[108, 2]) end @@ -386,10 +314,11 @@ "7" => "EPOS(海域[観測網外])", "8" => "EPOS(内陸[観測網内])", "9" => "予備", "/" =>"不明又は未設定" }.freeze + private_constant :OriginProbability # 震央の確からしさ def probability_of_position OriginProbability.fetch(@fastcast[113]) rescue KeyError @@ -451,11 +380,11 @@ else raise Error, "電文の形式が不正です(マグニチュード使用観測点[気象庁の部内システムでの利用])" end end - # 後方互換性のため + # 互換性のため alias probability_of_position_jma observation_points_of_magnitude # 震源の深さの確からしさ(※気象庁の部内システムでの利用) def probability_of_depth_jma case @fastcast[117] @@ -608,10 +537,89 @@ end @ebi.freeze return @ebi.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, :observation_points_of_magnitude, :probability_of_depth, :probability_of_magnitude, :probability_of_position, :probability_of_depth_jma, + :land_or_sea, :warning?, :prediction_method, :change, :reason_of_change, :ebi + ].freeze + private_constant :Attributes + + # 電文を解析した結果をHashで返します。 + def to_hash + unless @hash + @hash = {} + Attributes.each do |attribute| + @hash[attribute] = __send__(attribute) + end + @hash.freeze + end + return @hash.dup + end + + # 正しい電文であるかを返します + def valid? + unless @valid + begin + Attributes.each do |attribute| + __send__(attribute) + end + rescue Error + @valid = false + else + @valid = true + end + end + return @valid + end + + # 緊急地震速報の内容をテキストで出力します。 + def print + 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_depth_jma} +震央位置の海陸判定: #{land_or_sea} +警報を含む内容かどうか: #{warning?} +予測手法: #{prediction_method} +最大予測震度の変化: #{change} +最大予測震度の変化の理由: #{reason_of_change} + EOS + + if has_ebi? + @print << "\n地域毎の警報の判別、最大予測震度及び主要動到達予測時刻(EBI):\n" + ebi.each do |local| + arrival_time = local[:arrival] ? "すでに到達" : local[:arrival_time]&.strftime("%T") + @print << "#{local[:area_name].ljust(10)} 最大予測震度: #{local[:intensity].ljust(2)} 予想到達時刻: #{arrival_time} 警報: #{local[:warning]}\n" + end + end + + @print.freeze + return @print.dup + end + private # 電文フォーマットの震度を文字列に変換 def to_seismic_intensity(str) SeismicIntensity.fetch(str) @@ -637,12 +645,13 @@ return "#{to_seismic_intensity(local_str[7, 2])}から#{to_seismic_intensity(local_str[5, 2])}" end # 予想到達時刻 def ebi_arrival_time(local_str) - return nil if local_str[10, 6] == "//////" - return Time.local("20" + @fastcast[26, 2], @fastcast[28, 2], @fastcast[30, 2], local_str[10, 2], local_str[12, 2], local_str[14, 2]) + arrival_time = local_str[10, 6] + return nil if arrival_time == "//////" + return Time.strptime(arrival_time, "%H%M%S") rescue ArgumentError raise Error, "電文の形式が不正です (EBI: 地震発生時刻)" end def ebi_warning(local_str) @@ -670,11 +679,9 @@ raise Error, "電文の形式が不正です(EBI: 主要動の到達予測状況)" end end end end - -EEWParser = EEW::Parser if __FILE__ == $PROGRAM_NAME # テスト str = <<EOS #テスト用の電文(EBIを含む) 37 03 00 110415233453 C11 110415233416