miutti's picture
Source: kernel, desktop app, tools (snapshot of the GitHub repo)
df41178 verified
Raw History Blame Contribute Delete
6.5 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
conjugate.py -- 動詞の活用を、規則で作る
「移す」から「移して」「移した」「移しといて」…を、
ひとつずつ書き並べるのではなく、国語で習う活用表から自動で作る。
なぜ規則にしたか
────────────────
はじめは外のAIに「述語を225個ならべて」と頼んだ。
返ってきたのは52個で、しかも「寄せられるように」のような
命令にならない形が混ざっていた。
日本語の活用は規則で決まっている。
規則で作れば、抜けもなく、間違いもなく、ただでいくらでも作れる。
五段・一段・サ変の3つだけ扱う。頼みごとに使う動詞は、ほぼこれで足りる。
五段活用の音の変化(学校で習う「行段」の表):
書く → 書か 書き 書く 書け 書こ / て形は 書いて
移す → 移さ 移し 移す 移せ 移そ / て形は 移して
運ぶ → 運ば 運び 運ぶ 運べ 運ぼ / て形は 運んで
"""
# 五段活用。語尾の1文字 → (連用形の音, て形, た形)
GODAN = {
"う": ("い", "って", "った"),
"つ": ("ち", "って", "った"),
"る": ("り", "って", "った"),
"む": ("み", "んで", "んだ"),
"ぶ": ("び", "んで", "んだ"),
"ぬ": ("に", "んで", "んだ"),
"く": ("き", "いて", "いた"),
"ぐ": ("ぎ", "いで", "いだ"),
"す": ("し", "して", "した"),
}
# 五段の未然形(〜ない/〜せる の前)
GODAN_A = {"う": "わ", "つ": "た", "る": "ら", "む": "ま", "ぶ": "ば",
"ぬ": "な", "く": "か", "ぐ": "が", "す": "さ"}
# 五段の命令形
GODAN_E = {"う": "え", "つ": "て", "る": "れ", "む": "め", "ぶ": "べ",
"ぬ": "ね", "く": "け", "ぐ": "げ", "す": "せ"}
# 「て」の後に付く、頼みごとの言い方
TE_TAILS = [
"", "ください", "くれ", "くれる", "ほしい", "ほしいな", "もらえる",
"もらえます", "おいて", "おいてね", "ね", "よ", "な",
]
# 連用形の後に付く言い方
RENYOU_TAILS = ["たい", "ます", "ましょう", "なさい"]
def _split(verb):
"""動詞を (語幹, 種類) に分ける。
種類は "五段" / "一段" / "サ変" / None
"""
if verb.endswith("する"):
return verb[:-2], "サ変"
if len(verb) >= 2 and verb[-1] == "る":
# 「見る・食べる」のような一段は、直前が「い段・え段」
prev = verb[-2]
if _is_i_or_e(prev):
return verb[:-1], "一段"
return verb[:-1], "五段"
if verb and verb[-1] in GODAN:
return verb[:-1], "五段"
return verb, None
_I_ROW = set("いきしちにひみりぎじびぴ")
_E_ROW = set("えけせてねへめれげぜべぺ")
def _is_i_or_e(ch):
return ch in _I_ROW or ch in _E_ROW
def forms(verb):
"""ひとつの動詞から、頼みごとに使われる言い方を全部作る"""
stem, kind = _split(verb)
out = set()
if kind == "サ変":
te, ta, ren = stem + "して", stem + "した", stem + "し"
base = [verb, stem + "しろ", stem + "せよ", stem + "させて",
stem + "させといて", stem + "しといて"]
elif kind == "一段":
te, ta, ren = stem + "て", stem + "た", stem
base = [verb, stem + "ろ", stem + "よ", stem + "させて",
stem + "させといて", stem + "といて"]
elif kind == "五段":
last = verb[-1]
ren = stem + GODAN[last][0]
te = stem + GODAN[last][1]
ta = stem + GODAN[last][2]
base = [verb, stem + GODAN_E[last],
stem + GODAN_A[last] + "せて",
stem + GODAN_A[last] + "せといて",
te[:-1] + "といて" if te.endswith("て") else te]
else:
return {verb}
out.update(b for b in base if b)
for t in TE_TAILS:
out.add(te + t)
for t in RENYOU_TAILS:
out.add(ren + t)
# 「〜とく」の縮約(移しておく → 移しとく)
out.add(te[:-1] + "とく" if te.endswith("て") else te)
return {w for w in out if 2 <= len(w) <= 12}
# ------------------------------------------------------------------
# 動作ごとの、もとになる動詞
# ここだけ人が選ぶ。あとの活用は機械が作る
# ------------------------------------------------------------------
BASE_VERBS = {
"移動": ["移す", "移動する", "動かす", "まとめる", "集める", "寄せる",
"入れる", "しまう", "片付ける", "整理する", "放り込む",
"分ける", "仕分ける", "送る", "持っていく"],
"数える": ["数える", "カウントする", "調べる"],
"一覧": ["見せる", "並べる", "listする", "出す", "教える", "表示する"],
"作成": ["作る", "作成する", "用意する", "新規作成する", "こしらえる"],
"ごみばこ": ["捨てる", "消す", "削除する", "始末する", "処分する",
"ゴミ箱に入れる"],
"改名": ["改名する", "リネームする", "名前を変える", "つけ直す"],
"重複": ["重複する", "かぶる", "だぶる"],
"大きさ": ["合計する"],
"もぐる": ["もぐる", "潜る"],
"HTML": ["HTML化する", "ページにする"],
}
def build():
"""全部の動作について、述語カードを作る。
戻り値: {述語: 動作}
"""
out = {}
for act, verbs in BASE_VERBS.items():
for v in verbs:
for f in forms(v):
# 先に入った動作を優先する(早い者勝ちで衝突を避ける)
out.setdefault(f, act)
return out
if __name__ == "__main__":
import sys, json
if len(sys.argv) > 1:
for v in sys.argv[1:]:
print(f"\n{v} → " + " / ".join(sorted(forms(v))))
else:
t = build()
from collections import Counter
c = Counter(t.values())
print(f"できた述語: {len(t)} 個")
for act, n in c.most_common():
print(f" {act:<8} {n:>4} 個")
print("\n見本(移動):")
print(" " + " / ".join(sorted(k for k, v in t.items()
if v == "移動")[:24]))