作者: T.Watanabe
日時: 2005/4/19(23:12)
  ねこ丸です。

  先日の awk の話ですが、こんなもの作ってました。定期的に思いつくネタ
で、かつずいぶん昔にも同じものを同じ awk で作ったはずなのですが、探す
のも面倒だったので作り直しました。JavaScript で動いてるやつとかあちこ
ちのサイトにあるんですけど、こういう小物は手元でさっと動かせた方が嬉し
いので。

# でも必要なときにはこのスクリプトの存在を忘れているに違いない :-)

  本当は POSIX 拡張正規表現を使いたかったんですが、shebang で --posix
とか -Wposix とか書いてもうまく動かなかったので古典的な書き方に。gawk
のパスは適当に書き換えてください。(一応 Linux に合わせてあるつもり)

  使い方は

gengo.awk [mtsh][0-9]+

  と入力したときは元号 → 西暦変換を、

gengo.awk [0-9]{4}

  と入力したときは西暦 → 元号変換を行います。古い元号とかいちいち列挙
してもまず使わないので明治以降しか対応してません。

  また、西暦は各元号の元年には変換されません。見てみれば分かりますが、
例えば「1989」を変換するとき、「昭和」の範囲内に収まってしまうので、そ
こで判定を終了して「昭和64年」と返ってきます。昭和と平成と両方表示され
るようにしてもよかったんですけど、面倒くさいのでやめました。

  日本語使ってるので LC_CTYPE をセットした gawk 3.1 以降を使うか、マル
チバイト拡張版の gawk を使ってください。jgawk 2.x でも動くようなことが
コメントに書いてありますけど、確認してないので動いた人は教えてください。

# 3 ならでの機能は何一つ使ってないと思いますけど

--^ gengo.awk
#! /usr/bin/gawk -f
#
# Usage:
# gengo [[MTSH]year]
#
# Note:
# Requiring setting LC_CTYPE, if you use gawk 3.1 or later.
# No need, if you use multibyte extented version.( including jgawk2.x)
#
# Reference:
# http://homepage1.nifty.com/gyouseinet/history/gengouichiran.htm

#
# メイン
#
BEGIN {
  IGNORECASE = 1;

  set_gengo( begin, end, gengo );
  year = set_year();
  print year "年 = " conv_year( year );
}

#
# コマンドライン引数から調べる年をセット
#
function set_year() {
  ret = "";
  if ( ARGV[1] != "" ) {
    ret = ARGV[1];
  } else {
    ret = strftime( "%Y" );
  }

  return ret;
}

#
# 年の変換
#
function conv_year( year ) {
  ret = "";
  kind_of_year = detect_year( year );
  if ( kind_of_year == "era" ) {
    ret = era2gengo( year );
  } else if ( kind_of_year == "gengo" ) {
    ret = gengo2era( year );
  } else {
    ret = "年を判別できませんでした\n" year;
  }

  return ret;
}

#
# 年の判別
#
function detect_year( year ) {
  if ( year ~ /^[0-9][0-9][0-9][0-9]$/ ) {
    return "era";
  } else if ( year ~ /^[a-z][0-9]+$/ ) {
    return "gengo";
  } else {
    return "not valid.";
  }
}

#
# 西暦から元号へ変換
#
function era2gengo( year ) {
  is_converted = 0;
  ret          = year;

  for ( g in gengo ) {
    if ( begin[gengo[g]] <= year && year <= end[gengo[g]] ) {
      ret = year - begin[gengo[g]] + 1;
      ret = wareki[gengo[g]] ret "年";
      is_converted = 1;
      break;
    }
  }
  if ( !is_converted ) {
    ret = "変換できませんでした";
  }

  return ret;
}

#
# 元号から西暦へ変換
#
function gengo2era( year ) {
  is_converted = 0;
  ret          = year;
  alpha        = 0;
  num          = 0;

  # 元号の文字列を文字と数値に分割してみる
  match( year, /^[a-z]/ );
  if ( RSTART > 0 ) {
    alpha = tolower( substr( year, RSTART, RLENGTH ) );
    num   = substr( year, RSTART + RLENGTH );
    match( num, /^[0-9]+/ );
    if ( RSTART > 0 ) {
      num = substr( num, RSTART, RLENGTH );
    }
  }

  # うまく分割できたら変換
  if ( alpha != 0 && num != 0 ) {
    for ( i in gengo ) {
      if ( gengo[i] == alpha ) {
        ret = begin[gengo[i]] + num - 1;
        ret = "西暦" + ret + "年";
        is_converted = 1;
        break;
      }
    }
  }

  if ( !is_converted ) {
    ret = "変換できませんでした";
  }

  return ret;
}

#
# 元号関係のグローバルの連想配列をセット
# (終わっていない元号は適当な数字をセットしてある)
#
function set_gengo( begin, end, gengo ) {
  gengo[0]   = "m";
  gengo[1]   = "t";
  gengo[2]   = "s";
  gengo[3]   = "h";

  begin["m"] = 1868;
  begin["t"] = 1912;
  begin["s"] = 1926;
  begin["h"] = 1989;
  end["m"]   = 1912;
  end["t"]   = 1926;
  end["s"]   = 1989;
  end["h"]   = 2100; # 適宜書き換えて

  wareki["m"] = "明治";
  wareki["t"] = "大正";
  wareki["s"] = "昭和";
  wareki["h"] = "平成";
}
--$

# 無駄に行数食っててすいません

--
    ねこ丸