Snippets

sironekotoro 和暦を引数に与えると西暦年を応えてくれる

Created by sironekotoro last modified
#!/usr/bin/env perl
# guess-ad-year.pl - 和暦を引数に与えると西暦年を応えてくれる
# ad は A.D. (Anno Domini = 西暦年) の略
#
# 例:
# guess-ad-year.pl 平成30年
# 2018年
# guess-ad-year.pl 昭和54年
# 1979年

use strict;
use warnings;
use utf8;
use Encode qw/decode/;
binmode( STDOUT, ':encoding(utf8)' );
binmode( STDERR, ':encoding(utf8)' );

# 元号対応表
# keyを各年号, valueに開始年と短縮形を格納した
# ハッシュリファレンス, というデータ構造を作る
my %JAPANESE_ERA = (
    '明治' => { start => 1867, shortening => 'M' },
    '大正' => { start => 1911, shortening => 'T' },
    '昭和' => { start => 1925, shortening => 'S' },
    '平成' => { start => 1988, shortening => 'H' },
    '令和' => { start => 2018, shortening => 'R' },
);

# 全角数字から半角数字へ変換するためのハッシュを作る
my %NUMBER = (
    '0' => 0,
    '1' => 1,
    '2' => 2,
    '3' => 3,
    '4' => 4,
    '5' => 5,
    '6' => 6,
    '7' => 7,
    '8' => 8,
    '9' => 9,
    '0' => 0,
);

## 正規表現リファレンス
# 正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう
# https://blog.tokumaru.org/2014/03/z.html
# 名前付きキャプチャを利用
my $regex = qr/\A(?<era>\w{1,2}?)(?<year>\d+|元)年\z/;

# 入力を受け取る
my $input = shift;

# 入力文字列をデコードする
my $decoded_input = decode( 'utf8', $input );

# 正規表現に失敗した時のエラーメッセージ
my $regex_error = "昭和54年 などの形で入力してください\n";

# 正規表現

unless ( $decoded_input =~ /$regex/ ) {
    print $regex_error;
    exit;
}

# 名前付きキャプチャを普通のスカラー変数に移す
my $era  = $+{era};
my $year = $+{year};

# 元号が'M, T, S, H, R'の場合はそれぞれ修正する
$era = from_short_to_era($era);

# 元号が対応しているものかをチェックする
is_correct_era($era);

# 年数に「元」、つまり元年が入力された場合には1に置き換える
$year = from_gannen_to_one($year);

# 全角数値が入力されている場合は半角に置き換える
$year = to_quantify_year($year);

print '西暦' . ( $year + $JAPANESE_ERA{$era}->{start} ) . '年', "\n";

##
## サブルーチン
##

# 元号が'M, T, S, H, R'の場合はそれぞれ修正する
sub from_short_to_era {
    my $era = shift;

    # 1文字でなかったらそのまま返す
    return $era if length($era) > 1;

    # 大文字小文字どちらが入力されていても元号が判別できるように、
    # 元号表に合わせて大文字化する
    $era = ucfirst($era);

    # 元号対応表に対応する短縮形が入っていたら
    # その元号を返す
    for my $key ( keys %JAPANESE_ERA ) {
        return $key if $era eq $JAPANESE_ERA{$key}->{shortening};
    }
}

# 元号が対応しているものかをチェックする
sub is_correct_era {
    my $era = shift;
    if ( exists $JAPANESE_ERA{$era} ){
        return 1;
    }
    else{
        print "対応している元号は明治, 大正, 昭和, 平成, 令和 のみです\n";
        exit;
    };
}

# 年数に「元」、つまり元年が入力された場合には1に置き換える
sub from_gannen_to_one {
    my $year = shift;
    if ( $year eq '元' ) {

        return 1;
    }
    else {
        return $year;
    }
}

# 全角数値が入力されている場合は半角に置き換える
sub to_quantify_year {
    my $year = shift;

    # 入力された文字を1文字ずつ分割して配列に入れる
    my @number = split //, $year;

    # 返り値用の変数を用意する
    my $return_year = '';

    # 配列の要素を1つずつ処理する
    for my $num (@number) {

# 全角半角対応表にkeyが存在すれば、valueの値(半角数字)を
# 文字列連結して返す
        if ( exists $NUMBER{$num} ) {
            $return_year .= $NUMBER{$num};
        }
        else {
# keyが存在しない場合には、そのまま返り値に文字列連結する
            $return_year .= $num;
        }
    }
    return $return_year;
}

Comments (0)