lib/eew_parser.rb in eew_parser-0.1.9 vs lib/eew_parser.rb in eew_parser-0.2.0
- old
+ new
@@ -1,6 +1,6 @@
-#encoding: utf-8
+# encoding: utf-8
require_relative "epicenter_code"
require_relative "area_code"
# 緊急地震速報パーサ
@@ -26,10 +26,11 @@
# 引数には緊急地震速報の電文を与えます。
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
end
attr_reader :fastcast
@@ -70,10 +71,11 @@
マグニチュードの確からしさ: #{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?
@@ -88,37 +90,48 @@
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,
- :land_or_sea, :warning?, :change, :reason_of_change, :ebi
+ :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
- hash = {}
- Attributes.each do |attribute|
- hash[attribute] = __send__(attribute)
+ unless @hash
+ @hash = {}
+ Attributes.each do |attribute|
+ @hash[attribute] = __send__(attribute)
+ end
+ @hash.freeze
end
- return hash
+ return @hash.dup
end
# 正しい電文であるかを返します
- def verify
- Attributes.each do |attribute|
- __send__(attribute)
+ def valid?
+ unless @valid
+ begin
+ Attributes.each do |attribute|
+ __send__(attribute)
+ end
+ rescue Error
+ @valid = false
+ else
+ @valid = true
+ end
end
- return true
+ return @valid
end
def inspect
"#<EEWParser:#{id} (第#{number}報) #{epicenter} 震度#{seismic_intensity}>"
end
def ==(other)
- fastcast == other.fastcast
+ fastcast == other.fastcast
end
def <=>(other)
__id__ <=> other.__id__
end
@@ -137,10 +150,16 @@
else
raise Error, "電文の形式が不正です(電文種別コード)"
end
end
+ # キャンセル報かどうか
+ def canceled?
+ return true if @fastcast[0, 2] == "39"
+ return false
+ end
+
# 発信官署
def from
case @fastcast[3, 2]
when "01"
"札幌"
@@ -232,10 +251,11 @@
return id
rescue ArgumentError
raise Error, "電文の形式が不正です(地震識別番号: #{id})"
end
+ # 地震識別番号 + 通番
def __id__
(id * 10) + number
end
# 発表状況(訂正等)の指示
@@ -258,11 +278,11 @@
end
end
# 発表状況と訓練識別が通常かどうか
def normal?
- return true if @fastcast[59] == "0" && @fastcast[6, 2] == "00"
+ return true if (@fastcast[59] == "0" || @fastcast[59] == 9) && @fastcast[6, 2] == "00"
return false
end
# 第1報であればtrueを、そうでなければfalseを返します。
def first?
@@ -349,17 +369,10 @@
"6-" => "6弱",
"6+" => "6強",
"07" => "7"
}.freeze
- # 電文フォーマットの震度を文字列に変換
- def to_seismic_intensity(str)
- SeismicIntensity.fetch(str)
- rescue KeyError
- raise Error, "電文の形式が不正です(震度: #{str})"
- end
-
# 最大予測震度
def seismic_intensity
to_seismic_intensity(@fastcast[108, 2])
end
@@ -559,15 +572,12 @@
end
end
# EBIを含むかどうか
def has_ebi?
- if @fastcast[135, 3] == "EBI"
- return true
- else
- return false
- end
+ return true if @fastcast[135, 3] == "EBI"
+ return false
end
# 地域毎の警報の判別、最大予測震度及び主要動到達予測時刻
# EBIがあればHashを格納したArrayを、なければ空のArrayを返します。Hashに格納されるkeyとvalueはそれぞれ次のようになっています。
# :area_name 地域名称
@@ -580,52 +590,88 @@
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]] # 地域名称
- 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
- local[:intensity] = "#{to_seismic_intensity(@fastcast[i+7, 2])}から#{to_seismic_intensity(@fastcast[i+5, 2])}"
- end
- if @fastcast[i+10, 6] == "//////"
- local[:arrival_time] = nil # 予想到達時刻
- else
- local[:arrival_time] = Time.local("20" + @fastcast[26, 2], @fastcast[28, 2], @fastcast[30, 2], @fastcast[i+10, 2], @fastcast[i+12, 2], @fastcast[i+14, 2])
- end
- case @fastcast[i+17]
- when "0"
- local[:warning] = false # 警報を含むかどうか
- when "1"
- local[:warning] = true
- 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
- when "/", "2".."9"
- local[:arrival] = nil
- else
- raise Error, "電文の形式が不正でです(主要動の到達予測状況[EBI])"
- end
- @ebi << local
+ local_str = @fastcast[i, 20]
+ area_code = ebi_area_code(local_str)
+ local = {
+ area_code: area_code,
+ area_name: ebi_area_name(area_code),
+ intensity: ebi_intensity(local_str),
+ arrival_time: ebi_arrival_time(local_str),
+ warning: ebi_warning(local_str),
+ arrival: ebi_arrival(local_str)
+ }
+ local.freeze
+ @ebi.push(local)
i += 20
end
@ebi.freeze
return @ebi.dup
end
+
+ private
+
+ # 電文フォーマットの震度を文字列に変換
+ def to_seismic_intensity(str)
+ SeismicIntensity.fetch(str)
+ rescue KeyError
+ raise Error, "電文の形式が不正です(震度: #{str})"
+ end
+
+ def ebi_area_code(local_str)
+ return Integer(local_str[0, 3])
+ rescue ArgumentError
+ raise Error, "電文の形式が不正です(EBI: 地域コード)"
+ end
+
+ def ebi_area_name(area_code)
+ return AreaCode.fetch(area_code)
+ rescue KeyError
+ raise Error, "電文の形式が不正です(EBI: 地域名称)"
+ end
+
+ def ebi_intensity(local_str)
+ return to_seismic_intensity(local_str[5, 2]) + "以上" if local_str[7, 2] == "//" # 最大予測震度
+ return to_seismic_intensity(local_str[5, 2]) if local_str[5, 2] == local_str[7, 2]
+ 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])
+ rescue ArgumentError
+ raise Error, "電文の形式が不正です (EBI: 地震発生時刻)"
+ end
+
+ def ebi_warning(local_str)
+ case local_str[17]
+ when "0"
+ return false
+ when "1"
+ return true
+ when "/", "2".."9"
+ return nil
+ else
+ raise Error, "電文の形式が不正です(EBI: 警報の判別)"
+ end
+ end
+
+ def ebi_arrival(local_str)
+ case local_str[18]
+ when "0"
+ return false
+ when "1"
+ return true
+ when "/", "2".."9"
+ return nil
+ else
+ raise Error, "電文の形式が不正です(EBI: 主要動の到達予測状況)"
+ end
+ end
end
end
EEWParser = EEW::Parser
@@ -644,42 +690,9 @@
9999=
EOS
fc = EEW::Parser.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}
-コードが続くかどうか: #{fc.continue?}
-地震発生時刻もしくは地震検知時刻: #{fc.earthquake_time}
-地震識別番号: #{fc.id}
-発表状況(訂正等)の指示: #{fc.status}
-発表する高度利用者向け緊急地震速報の番号(地震単位での通番): #{fc.number}
-震央地名コード: #{fc.epicenter}
-震央の位置: #{fc.position}
-震源の深さ(単位 km)(不明・未設定時,キャンセル時:///): #{fc.depth}
-マグニチュード(不明・未設定時、キャンセル時:///): #{fc.magnitude}
-最大予測震度(不明・未設定時、キャンセル時://): #{fc.seismic_intensity}
-震央の確からしさ: #{fc.probability_of_position}
-震源の深さの確からしさ: #{fc.probability_of_depth}
-マグニチュードの確からしさ: #{fc.probability_of_magnitude}
-震央の確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_position_jma}
-震源の深さの確からしさ(気象庁の部内システムでの利用): #{fc.probability_of_depth_jma}
-震央位置の海陸判定: #{fc.land_or_sea}
-警報を含む内容かどうか: #{fc.warning?}
-最大予測震度の変化: #{fc.change}
-最大予測震度の変化の理由: #{fc.reason_of_change}
-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.fastcast
+ pp fc.to_hash
puts fc.print
- p EEW::AreaCode.values.max_by(&:size).size
end