python#2.6 決まり字判定機ver1

 「決まり字」とは、「その文字まで聞けばそれが一つのものに特定できる、という文字」のことです。

 たとえば、百人一首の中に、「千早ぶる 神代もきかず 龍田川  からくれなゐに 水くくるとは」という句があります。

 一文字目の「ち」では、まだ「ちはやぶる」とは確定できません。百種の中に「ち」で始まる句が他に2つあるからです。「契りきな かたみに袖を しぼりつつ 末の松山 波越さじとは」と「契りおきし させもが露を 命にて あはれ今年の 秋も去ぬめり」です。

 二文字目の「ちは」まで見ると、他の二首(ち'ぎ'りきな、ち'ぎ'りおきし)とは異なることがわかります。したがって、「ちはやぶる」の句の決まり字は「ちは」となります。

 このような決まり字を導くためのプログラムを書いてみました。

import tkinter as tk
import tkinter.filedialog

# 文字列 2 つを比較して決まり字を導く関数 kmrj を定義する
def kmrj(strA, strB):
   
   # strA と strB が同一である場合、いずれの決まり字も 'strA(重複)' と記述する
   if strA == strB:
       return ((strA + '(重複)'), (strB + '重複'))
   
   # strB が strA で始まる場合、strA の決まり字は 'strA」' と記述する
   # strB の決まり字は、strB を (strA の文字数 + 1) 文字目までスライスした部分になる
   # 例 : 'py' と 'python' を比べるとき、決まり字はそれぞれ 'py」', 'pyt' とする
   elif strB.startswith(strA):
       return ((strA + '」'), strB[:len(strA)+1])

   # それ以外の場合
   # 注. ソートしているので、strA が strB から始まることはない    
   else:
       for i in range(len(strA)):
           if strA[:i+1] != strB[:i+1]:
               return (strA[:i+1], strB[:i+1])
               break

# データを読み込んだ後、ソートする関数 read_and_sort を定義する
def read_and_sort():
   results = []
   with open(filename, 'r') as f:
       for row in f:
           item = row.rstrip()
           results.append(item)
   sorted_results = sorted(results)
   return sorted_results

# ソートされたリストから決まり字のリストを作り、それらを一つのリストに保存する関数 kimariji_main を作る
def kimariji_main():
   sorted_results = read_and_sort()
   converted_results = []
   # 要素が1つだけの場合、1字決まり
   if len(sorted_results) == 1:
       converted_results.append(sorted_results[0][0])
   # 要素が2つの場合、kmrj 関数の戻り値がそのまま結果になる (タプル型をリスト型に変える必要あり)
   elif len(sorted_results) == 2:
       converted_results = list(kmrj(sorted_results[0], sorted_results[1]))
   # 要素が3つ以上の場合
   else:
       for i in range(len(sorted_results)):
           if i == 0:
               # 最初は sorted_results[0] と sorted_results[1] で比べるだけで良い
               converted_results.append(kmrj(sorted_results[0], sorted_results[1])[0])
           elif 1 <= i <= len(sorted_results) - 2:
               # kmrj 関数の戻り値をタプルにしているのはこの2行のため
               a, B = kmrj(sorted_results[i-1], sorted_results[i])
               b, C = kmrj(sorted_results[i], sorted_results[i+1])
               # B が b で始まる / 一致する (= B の方が b より長い) 場合、決まり字は B
               if B.startswith(b):
                   converted_results.append(B)
               # b の方が B より長い場合、決まり字は b
               else:
                   converted_results.append(b)
   # 元のデータ (sorted_results) と、決まり字のデータ (converted_results) を合わせて表示する
   main_results = []
   for sorted_result, converted_result in zip(sorted_results, converted_results):
       main_results.append(sorted_result + '\t' + converted_result)
   return main_results
   

if __name__ == '__main__':

   # 決まり字を作成したいデータが保存されているファイルを選択する
   root = tk.Tk()
   root.withdraw()
   filename = tkinter.filedialog.asksaveasfilename()
   root.destroy()
   if filename:
       pass
   else:
       print('No file specified')
   try:
       main_results = kimariji_main()
   except IOError:
       print('ファイルを開くことができません')

   # 書き出し先のファイルを選択する
   root = tk.Tk()
   root.withdraw()
   filename = tkinter.filedialog.asksaveasfilename()
   root.destroy()
   if filename:
       pass
   else:
       print('No file specified')
   try:
       with open(filename, 'a') as f:
           for i in range(len(main_results)):
               f.write(main_results[i] + '\n')
   except IOError:
       print('ファイルを開くことができません')

 なお、仕様には改良が望まれる点がいくつかあります。

① 元のデータに漢字が入っていても、読みまで反映してくれないので、一度読み仮名に直す必要がある

② 出てくる決まり字データでは、英語の大文字小文字は区別される

③ 元データとの紐付け

 対処法も示しておきます。

 ①は、数件前の記事にあるルビ振り機を使用することで対応可能です。むしろ、ルビ振り機は決まり字判定機を使うための前準備として制作しました。

 ②は、アルファベットをすべて小文字に直したデータを初めに作っておき、そのデータを使って決まり字が何文字目までかを判定・記録し、後で大文字・小文字が混在する元のデータにある文字列からその文字数だけ取り出す、というプログラムを書けば成り立ちますが、面倒なので省略しています。

 そもそもみんはや(みんなで早押しクイズ)の回答・作問時に役立つだろうと思っての制作で、みんはやでは大文字・小文字はしっかり区別されるので(作問者が大雑把でない限り)②はそのままの方がむしろいいです。

 ③は、辞書を使えばなんとかなるはずなんですけど、面倒なので ver2 に回します。

 使用例は下記の通り。左端が元のデータ ( 1/3 程度見切れています) で、中央がルビ振り機で漢字をひらがなに直し記号を取り除いたもの、右端が中央のデータを並び替えて決まり字に変換したものです。

スクリーンショット 2021-01-05 16.05.34


この記事が気に入ったらサポートをしてみませんか?