和暦(漢字+漢数字)を和暦(半角英数字)へ

こんにちは.株式会社ガラパゴスの[twitter:@kokosamu]です.
iOSチームのリーダーになってしまったので,
早速ですがRuby*1のちょっとした便利関数を用意してみました.

和暦変換の対象

今回の記事の対象は漢字と漢数字からなる和暦の変換です.
以下のような変換を想定しています.

"平成二十一年三月十二日" -> "H21.3.12"
"昭和元年一一月二〇日" -> "S1.11.20"
"大正三年一月八日" -> "T3.1.18"

このような和暦変換を行なうことで和暦(漢字+漢数字)をDateクラスで扱うことができます.
Dataクラスは和暦(半角英数字)のparseをサポートしているためです.

require 'date'
d = Date.parse("H21.3.1")
puts d.to_s #2009-03-01

ところで,この和暦変換を考える上での最大の障害は日本語特有の表記ゆれです.

  • 「元年」 or 「一年」
  • 「十」 or 「一〇」
  • 「二十一」 or 「二一」

どれも正しい表記法のため,こうした表記ゆれを考慮して変換する必要があります.
実際,漢字と漢数字からなる和暦を半角英数字の和暦に変換するコードは見当たりませんでした*2
上記のような表記ゆれを考慮し,和暦変換を行なうのが以下のコードになります.

変換コード

NUM_KAN = ['','','','','','','','','','','','']
NENGO_CHAR = {'明治'=>'M','大正'=>'T','昭和'=>'S','平成'=>'H'}

def datestrZenToHan(from, to='')
  if from.class==String then from=from.split(//) end
  if !NUM_KAN.index(from[0]).nil?
    if from[0] == ''
      to += (to[-1,1][/\d/].nil?)?('10'):('0')
    else
      if !to[/0$/].nil? then to[-1,1]='' end
      to += (from[0]=='')?('1'):NUM_KAN.index(from[0]).to_s
    end
  elsif !['',''].index(from[0]).nil?
    to += '.'
  elsif from.size>1 && NENGO_CHAR.key?(from[0]+from[1])
    to = NENGO_CHAR[(from[0]+from[1])]
    from.delete_at 0
  else
    return to
  end
  from.delete_at 0
  return datestrZenToHan(from, to)
end

使用法は以下のとおり.

puts datestrZenToHan "平成二十一年三月十二日" #H21.3.12
puts datestrZenToHan "昭和元年一一月二〇日" #S1.11.20
puts datestrZenToHan "大正三年一月八日" #T3.1.8
puts datestrZenToHan "明治十年一〇月三十一日" #M10.10.31

require 'date'
puts Date.parse(datestrZenToHan "平成二十三年五月二日").to_s #2011-05-02
puts Date.parse(datestrZenToHan "昭和六十三年四月二六日").to_s #1988-04-26

簡単のため元号・月・日はどれも99以下であると仮定しています*3

なお間違った入力があった場合のエラー処理は行っていません.
したがって間違った入力に対する出力は保障しません.
またRubyライクに書くのであればDateクラスを拡張するのがスジでしょうが
面倒 多言語に移植しやすいよう再帰関数のみで書いています.

まとめ

というわけで今回は和暦(漢字+漢数字)を和暦(半角英数字)へ変換するRubyコードを紹介しました.
次こそiOSに関する技術を紹介する……かも.

*1:こまけぇこたぁいいんだよ!

*2:ネットは広大です.探せば存在するのでしょうが,5分程度さまよったところでは見つかりませんでした.

*3:天皇陛下が100年以上在位されれば変更が必要でしょうが,少なくとも向こう80年は考慮しなくても良いはずです.