2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Python 元号(和暦)年を西暦に変換する

Last updated at Posted at 2021-08-09

和暦を西暦に変換する

文章中からなるべく正規表現を使わずにdictを使った変換処理を考えてみた。
これにより元号が増えても、処理時間に影響はない、はず。変換対象文字数に対して線形時間

  • 日付までの処理は非対応
  • 年数の変換に特化
  • 大化の改新から令和まで対応
  • 各元号の開始年はWikipediaの始期を参考
  • python3オンリー
# coding=utf8

from datetime import datetime, timedelta

g2d = {
    '令和': datetime(2019, 5, 1), 'R.': datetime(2019, 5, 1),
    '平成': datetime(1989, 1, 8), 'H.': datetime(1989, 1, 8),
    '昭和': datetime(1926, 12, 25), 'S.': datetime(1926, 12, 25),
    '大正': datetime(1912, 7, 30), 'T.': datetime(1912, 7, 30),
    '明治': datetime(1868, 10, 23), 'M.': datetime(1868, 10, 23),
    '慶応': datetime(1865, 5, 1), '元治': datetime(1864, 3, 27), '文久': datetime(1861, 3, 29), '万延': datetime(1860, 4, 8), '安政': datetime(1855, 1, 15), '嘉永': datetime(1848, 4, 1), '弘化': datetime(1845, 1, 9), '天保': datetime(1831, 1, 23), '文政': datetime(1818, 5, 26), '文化': datetime(1804, 3, 22), '享和': datetime(1801, 3, 19), '寛政': datetime(1789, 2, 19), '天明': datetime(1781, 4, 25), '安永': datetime(1772, 12, 10), '明和': datetime(1764, 6, 30), '宝暦': datetime(1751, 12, 14), '寛延': datetime(1748, 8, 5), '延享': datetime(1744, 4, 3), '寛保': datetime(1741, 4, 12), '元文': datetime(1736, 6, 7), '享保': datetime(1716, 8, 9), '正徳': datetime(1711, 6, 11), '宝永': datetime(1704, 4, 16), '元禄': datetime(1688, 10, 23), '貞享': datetime(1684, 4, 5), '天和': datetime(1681, 11, 9), '延宝': datetime(1673, 10, 30), '寛文': datetime(1661, 5, 23), '万治': datetime(1658, 8, 21), '明暦': datetime(1655, 5, 18), '承応': datetime(1652, 10, 20), '慶安': datetime(1648, 4, 7), '正保': datetime(1645, 1, 13), '寛永': datetime(1624, 4, 17), '元和': datetime(1615, 9, 5), '慶長': datetime(1596, 12, 16), '文禄': datetime(1593, 1, 10), '天正': datetime(1573, 8, 25), '元亀': datetime(1570, 5, 27), '永禄': datetime(1558, 3, 18), '弘治': datetime(1555, 11, 7), '天文': datetime(1532, 8, 29), '享禄': datetime(1528, 9, 3), '大永': datetime(1521, 9, 23), '永正': datetime(1504, 3, 16), '文亀': datetime(1501, 3, 18), '明応': datetime(1492, 8, 12), '延徳': datetime(1489, 9, 16), '長享': datetime(1487, 8, 9), '文明': datetime(1469, 6, 8), '応仁': datetime(1467, 4, 9), '文正': datetime(1466, 3, 14),
    '寛正': datetime(1461, 2, 1), '長禄': datetime(1457, 10, 16), '康正': datetime(1455, 9, 6), '享徳': datetime(1452, 8, 10), '宝徳': datetime(1449, 8, 16), '文安': datetime(1444, 2, 23), '嘉吉': datetime(1441, 3, 10), '永享': datetime(1429, 10, 3), '正長': datetime(1428, 6, 10), '応永': datetime(1394, 8, 2), '明徳': datetime(1390, 4, 12), '康応': datetime(1389, 3, 7), '嘉慶': datetime(1387, 10, 5), '至徳': datetime(1384, 3, 19), '永徳': datetime(1381, 3, 20), '康暦': datetime(1379, 4, 9), '永和': datetime(1375, 3, 29), '応安': datetime(1368, 3, 7), '貞治': datetime(1362, 10, 11), '康安': datetime(1361, 5, 4), '延文': datetime(1356, 4, 29), '文和': datetime(1352, 11, 4), '観応': datetime(1350, 4, 4), '貞和': datetime(1345, 11, 15), '康永': datetime(1342, 6, 1), '暦応': datetime(1338, 10, 11), '元中': datetime(1384, 5, 18), '弘和': datetime(1381, 3, 6), '天授': datetime(1375, 6, 26), '文中': datetime(1372, 5, 1), '建徳': datetime(1370, 8, 16), '正平': datetime(1347, 1, 20), '興国': datetime(1340, 5, 25), '延元': datetime(1336, 4, 11), '建武': datetime(1334, 3, 5), '正慶': datetime(1332, 5, 23), '元弘': datetime(1331, 9, 11), '元徳': datetime(1329, 9, 22), '嘉暦': datetime(1326, 5, 28), '正中': datetime(1324, 12, 25), '元亨': datetime(1321, 3, 22), '元応': datetime(1319, 5, 18), '文保': datetime(1317, 3, 16), '正和': datetime(1312, 4, 27), '応長': datetime(1311, 5, 17), '延慶': datetime(1308, 11, 22), '徳治': datetime(1307, 1, 18), '嘉元': datetime(1303, 9, 16), '乾元': datetime(1302, 12, 10), '正安': datetime(1299, 5, 25), '永仁': datetime(1293, 9, 6), '正応': datetime(1288, 5, 29), '弘安': datetime(1278, 3, 23), '建治': datetime(1275, 5, 22), '文永': datetime(1264, 3, 27), '弘長': datetime(1261, 3, 22), '文応': datetime(1260, 5, 24), '正元': datetime(1259, 4, 20), '正嘉': datetime(1257, 3, 31), '康元': datetime(1256, 10, 24), '建長': datetime(1249, 5, 2), '宝治': datetime(1247, 4, 5), '寛元': datetime(1243, 3, 18), '仁治': datetime(1240, 8, 5), '延応': datetime(1239, 3, 13), '暦仁': datetime(1238, 12, 30), '嘉禎': datetime(1235, 11, 1), '文暦': datetime(1234, 11, 27), '天福': datetime(1233, 5, 25), '貞永': datetime(1232, 4, 23), '寛喜': datetime(1229, 3, 31), '安貞': datetime(1228, 1, 18), '嘉禄': datetime(1225, 5, 28), '元仁': datetime(1224, 12, 31), '貞応': datetime(1222, 5, 25), '承久': datetime(1219, 5, 27), '建保': datetime(1214, 1, 18), '建暦': datetime(1211, 4, 23), '承元': datetime(1207, 11, 16), '建永': datetime(1206, 6, 5), '元久': datetime(1204, 3, 23), '建仁': datetime(1201, 3, 19), '正治': datetime(1199, 5, 23), '建久': datetime(1190, 5, 16), '文治': datetime(1185, 9, 9), '元暦': datetime(1184, 5, 27), '寿永': datetime(1182, 6, 29), '養和': datetime(1181, 8, 25), '治承': datetime(1177, 8, 29), '安元': datetime(1175, 8, 16), '承安': datetime(1171, 5, 27), '嘉応': datetime(1169, 5, 6), '仁安': datetime(1166, 9, 23), '永万': datetime(1165, 7, 14), '長寛': datetime(1163, 5, 4), '応保': datetime(1161, 9, 24), '永暦': datetime(1160, 2, 18),
    '平治': datetime(1159, 5, 9), '保元': datetime(1156, 5, 18), '久寿': datetime(1154, 12, 4), '仁平': datetime(1151, 2, 14), '久安': datetime(1145, 8, 12), '天養': datetime(1144, 3, 28), '康治': datetime(1142, 5, 25), '永治': datetime(1141, 8, 13), '保延': datetime(1135, 6, 10), '長承': datetime(1132, 9, 21), '天承': datetime(1131, 2, 28), '大治': datetime(1126, 2, 15), '天治': datetime(1124, 5, 18), '保安': datetime(1120, 5, 9), '元永': datetime(1118, 4, 25), '永久': datetime(1113, 8, 25), '天永': datetime(1110, 7, 31), '天仁': datetime(1108, 9, 9), '嘉承': datetime(1106, 5, 13), '長治': datetime(1104, 3, 8), '康和': datetime(1099, 9, 15), '承徳': datetime(1097, 12, 27), '永長': datetime(1097, 1, 3), '嘉保': datetime(1095, 1, 23), '寛治': datetime(1087, 5, 11), '応徳': datetime(1084, 3, 15), '永保': datetime(1081, 3, 22), '承暦': datetime(1077, 12, 5), '承保': datetime(1074, 9, 16), '延久': datetime(1069, 5, 6), '治暦': datetime(1065, 9, 4), '康平': datetime(1058, 9, 19), '天喜': datetime(1053, 2, 2), '永承': datetime(1046, 5, 22), '寛徳': datetime(1044, 12, 16), '長久': datetime(1040, 12, 16), '長暦': datetime(1037, 5, 9), '長元': datetime(1028, 8, 18), '万寿': datetime(1024, 8, 19), '治安': datetime(1021, 3, 17), '寛仁': datetime(1017, 5, 21), '長和': datetime(1013, 2, 8), '寛弘': datetime(1004, 8, 8), '長保': datetime(999, 2, 1), '長徳': datetime(995, 3, 25), '正暦': datetime(990, 11, 26), '永祚': datetime(989, 9, 10), '永延': datetime(987, 5, 5), '寛和': datetime(985, 5, 19), '永観': datetime(983, 5, 29), '天元': datetime(978, 12, 31), '貞元': datetime(976, 8, 11), '天延': datetime(974, 1, 16), '天禄': datetime(970, 5, 3), '安和': datetime(968, 9, 8), '康保': datetime(964, 8, 19), '応和': datetime(961, 3, 5), '天徳': datetime(957, 11, 21), '天暦': datetime(947, 5, 15), '天慶': datetime(938, 6, 22), '承平': datetime(931, 5, 16), '延長': datetime(923, 5, 29), '延喜': datetime(901, 8, 31), '昌泰': datetime(898, 5, 20), '寛平': datetime(889, 5, 30), '仁和': datetime(885, 3, 11), '元慶': datetime(877, 6, 1), '貞観': datetime(859, 5, 20), '天安': datetime(857, 3, 20), '斉衡': datetime(854, 12, 23), '仁寿': datetime(851, 6, 1), '嘉祥': datetime(848, 7, 16), '承和': datetime(834, 2, 14), '天長': datetime(824, 2, 8), '弘仁': datetime(810, 10, 20), '大同': datetime(806, 6, 8), '延暦': datetime(782, 9, 30), '天応': datetime(781, 1, 30), '宝亀': datetime(770, 10, 23), '神護景雲': datetime(767, 9, 13), '天平神護': datetime(765, 2, 1), '天平宝字': datetime(757, 9, 6), '天平勝宝': datetime(749, 8, 19), '天平感宝': datetime(749, 5, 4), '天平': datetime(729, 9, 2), '神亀': datetime(724, 3, 3), '養老': datetime(717, 12, 24), '霊亀': datetime(715, 10, 3), '和銅': datetime(708, 2, 7), '慶雲': datetime(704, 6, 16), '大宝': datetime(701, 5, 3), '朱鳥': datetime(686, 8, 14), '白雉': datetime(650, 3, 22),
    '大化': datetime(645, 7, 17)
}

g2yidx = {k[1]:{} for k in g2d}
end = datetime(9999, 12, 31)
for k, v in g2d.items():
    g2yidx[k[1]][k[0]] = [len(k), k, v, end - timedelta(seconds=1) if end else end]
    end = v
g2yidx["."]["R"][3] = datetime(9999, 12, 31)
g2yidx["."]["H"][3] = g2d["令和"] - timedelta(seconds=1)
g2yidx["."]["S"][3] = g2d["平成"] - timedelta(seconds=1)
g2yidx["."]["T"][3] = g2d["昭和"] - timedelta(seconds=1)
g2yidx["."]["M"][3] = g2d["大正"] - timedelta(seconds=1)

g2ynum = {
    '': 0, '': 1, '': 2, '': 3, '': 4, '': 5,
    '': 6, '': 7, '': 8, '': 9, '': 0, '': 1,
    '': 2, '': 3, '': 4, '': 5, '': 6, '': 7,
    '': 8, '': 9, '0': 0, '1': 1, '2': 2, '3': 3,
    '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
    '': 0, '': 1, '': 2, '': 3,
    ' ': -1, ' ': -1, '': -1, '': -1, '': 1
}

def gengo2date(s, strict = False):

    slen = len(s)
    if slen < 3:
        return s

    ret = ""
    i = -1

    while (i < slen - 3):
        i += 1

        s1 = s[i + 1]
        if (s1 not in g2yidx):
            ret += s[i]
            continue

        s0 = s[i]
        s1idx = g2yidx[s1]
        if (s0 not in s1idx):
            ret += s0
            continue

        sidx = s1idx[s0]
        elen, era, startdt, enddt = sidx
        i += 2

        if (elen == 4):
            if (s[i - 2] == era[0] and s[i - 1] == era[1]):
                i += 2
            else:
                ret += s0 + s1
                continue

        sy = s[i]
        r = 0
        while (sy in g2ynum):
            y = g2ynum[sy]
            if y != -1:
                r = 10 * r + y
            i += 1
            sy = s[i]

        if (r == 0):
            ret += s0
            i -= elen
            continue

        if (strict and enddt.year < startdt.year + r - 1):
            raise ValueError(f"`{era}` ended in B.C.`{enddt.year}`. years")
        ret += str(startdt.year + r - 1)
        i -= 1

    if (i < slen - 1):
        ret += s[i + 1:slen]

    return ret


print(gengo2date("令和元年05月1日"))     # -> 2019年05月1日
print(gengo2date("平成元年01月1日"))     # -> 1989年01月1日
print(gengo2date("令和2年04月1日"))     # -> 2020年04月1日
print(gengo2date("令和二十三年04月1日"))  # -> 2041年04月1日
print(gengo2date("令和三二年04月1日"))   # -> 2050年04月1日
print(gengo2date("令和 三二年04月1日"))  # -> 2050年04月1日
print(gengo2date("あいうえお令和 三 二年04月1日かきくけこ"))  # -> あいうえお2050年04月1日かきくけこ
print(gengo2date("令和 三 十 二 年04月1日"))  # -> 2050年04月1日
print(gengo2date("R.4 年04月1日"))  # -> 2022年04月1日
print(gengo2date("R.4/04/01"))  # -> 2022/04/01
print(gengo2date("R .4-04-01"))  # -> R .4-04-01(変換しない)
print(gengo2date("平成ほげ年"))  # -> 平成ほげ年(変換しない)
print(gengo2date("R.H"))        # -> R.H(変換しない)
print(gengo2date("R.1グランプリ"))  # -> 2019グランプリ(こういう場合は変換される)
print(gengo2date("R1グランプリ"))  # -> R1グランプリ(これは大丈夫)
print(gengo2date("初代M.1王者"))       # -> 初代1868王者(こういう場合は変換される)
print(gengo2date("初代M1王者"))  # -> 初代M1王者(これは大丈夫)
print(gengo2date("大化1377年"))  # -> 2021年(存在しない年数を入れても変換される)
print(gengo2date("大化1377年", strict = True))  # -> ValueError: `大化` ended in B.C.`650`. years(オプション付ければありえない年数の場合はエラーを出すことも可能。)

In [1]: %timeit gengo2date("平成二十三年04月1日")
2.59 µs ± 51.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

全く面倒なルール作りやがってエコじゃないなあ

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?