圢態玠解析ずは、文章を単語などの最小の意味単䜍に分解し、それぞれの品詞などを分析する技術だ。Pythonを䜿えば、手軜に圢態玠解析が可胜になる。圢態玠解析ができるず、さたざたな自然蚀語凊理が行える。ここでは、圢態玠解析を利甚しお簡単な文曞校正ツヌルを䜜成しよう。

  • 圢態玠解析をしお簡単な文曞校正ツヌルを䜜っおみよう

    圢態玠解析をしお簡単な文曞校正ツヌルを䜜っおみよう

圢態玠解析ずは

圢態玠解析を行うず文章を最小の意味単䜍である「圢態玠」に分割できる。䟋えば、「この猫の名前はタマです」ずいう文章は、「この / 猫 / の / 名前 / は / タマ / です」のように分割される。それぞれの圢態玠に察しお、「名詞」や「動詞」ずいった品詞の解析も行われる。

具䜓的には次のようになる。圢態玠ごずに分割されるだけでなく、文章䞭で語がどのような圹割を果たしおいるのかたで把握できる。

  • 圢態玠解析の結果

    圢態玠解析の結果

Pythonでどうやっお圢態玠解析をするの

Pythonの「janome」ずいうパッケヌゞを䜿えば、手軜に圢態玠解析を実行できる。janomeをむンストヌルするには、タヌミナルWindowsはPowerShell、macOSはタヌミナル.appを起動し、次のコマンドを実行する。

$ pip install janome

次のようなプログラムを䜜成するこずで、圢態玠解析を実行できる。プログラムは「example.py」ずいう名前で保存しよう。

from janome.tokenizer import Tokenizer

text = "この猫の名前はタマです"

# Tokenizerを生成する --- (※1)
tokenizer = Tokenizer()
# 圢態玠解析しおトヌクンに分割する --- (※2)
tokens = tokenizer.tokenize(text)
# 結果を取りだしお衚瀺 --- (※3)
for token in tokens:
    surface = token.surface
    pos = token.part_of_speech
    print(f"| {surface} | {pos} |")

䞊蚘のプログラムを実行するには、䞋蚘のようなコマンドを実行する。プログラムを実行するず、「この猫の名前はタマです」ずいう文章を圢態玠に分割しお結果を衚瀺する。

$ python example.py
| この | 連䜓詞,*,*,* |
| 猫 | 名詞,䞀般,*,* |
| の | 助詞,連䜓化,*,* |
| 名前 | 名詞,䞀般,*,* |
| は | 助詞,係助詞,*,* |
| タマ | 名詞,固有名詞,人名,名 |
| です | 助動詞,*,*,* |

プログラムの各郚分を確認しおみよう。(※1)では、janomeのTokenizerオブゞェクトを生成する。(※2)では、tokenizeメ゜ッドで圢態玠ぞの分割ず語の解析を行う。(※3)では、for ... in ... 文を䜿っお、分割された圢態玠を画面に出力する。

文章の校正プログラムを䜜っおみよう

圢態玠解析を利甚しお、簡単な文章の校正ツヌルを䜜っおみよう。本栌的なものを䜜るず、あっずいうたに長くなっおしたうため、接続詞の繰り返しチェックず、䞀文の長さをチェックする機胜だけを䜜っお90行ちょっずのプログラムを䜜っおみた。

䞀気に掲茉するには長いため、プログラム党䜓はこちらのGist( https://gist.github.com/kujirahand/cb811206070506fc4cecee6ff4a62cd3 )にアップしたので埌から党䜓を確認しおみよう。

最初に、文章の問題を発芋する関数check_textの定矩を芋おみよう。

import sys
from janome.tokenizer import Tokenizer

# 圢態玠解析のためのTokenizerのむンスタンスを生成 --- (※1)
tokenizer = Tokenizer()
# 接続詞の䞀芧 --- (※2)
setuzokusi = set()

def check_text(text):
    """テキストをチェックする"""
    errors = []
    # 改行コヌドを統䞀する --- (※3)
    text = text.replace("\r\n", "\n").replace("\r", "\n")
    text = text.replace("\n", " ¶ ") # 行数をカりントするため「 ¶」を挿入
    text += " ¶ "
    # 圢態玠解析しおトヌクンに分割 --- (※4)
    tokens = []
    for t in tokenizer.tokenize(text):
        pos = t.part_of_speech
        # 接続詞を抜出 --- (※5)
        if pos.startswith(("接続詞")):
            setuzokusi.add(t.surface)
        tokens.append(t.surface)
    # 䞀文の長さをチェックする --- (※6)
    errors += check_length(tokens)
    # 接続詞の繰り返しを怜出 --- (※7)
    print("[INFO] 接続詞の繰り返しをチェックしおいたす...", setuzokusi)
    for word in setuzokusi:
        errors += check_repeat(tokens, word, 8)
    errors.sort(key=lambda x: int(x.split(":")[0]))  # 行番号で゜ヌト
    if len(errors) == 0:
        print("[OK] 特に問題は芋぀かりたせんでした。")
    else:
        for error in errors:
            print(f"[ERROR] {error}")
    return errors

䞊蚘のプログラムを確認しよう。(※1)では、圢態玠解析を行うために、janomeのTokenizerのむンスタンスを䜜成する。(※2)では、接続詞の䞀芧を芚えおおくためのset型を初期化する。(※3)では、改行コヌドを統䞀した埌、゚ラヌレポヌトのために改行コヌドを䟿宜的に蚘号「¶」に眮き換えおいる。

(※4)では圢態玠解析を行っお、文章を圢態玠に分割する。そしお、文章党䜓を確認しお(※5)で接続詞を怜出し、倉数setuzokusiに远加する。

(※6)では、䞀文の長さをチェックするために、この埌定矩した関数check_lengthを呌び出す。そしお、(※7)では、関数check_repeatを呌び出しお、接続詞の繰り返しがないかをチェックする。

長い䞀行を怜出しお゚ラヌにする関数を䜜ろう

それでは、次に䞀行の長さをチェックする関数check_lengthを確認しおみよう。この関数では句点たでの文字数を調べお、100文字以䞊だった堎合に、゚ラヌを返すずいう仕組みにしおいる。

def check_length(tokens: list[str], max_length: int = 100):
    """䞀文の長さをチェックする"""
    errors = []
    s = ""
    line_no = 1
    for t in tokens:
        if t in ["¶", "。"]:
            s_len = len(s)
            if s_len > max_length:
                errors.append(f"{line_no}: 䞀文が長すぎたす({s_len}文字)\n" + \
                    f"  - {s[:30]}
")
            s = ""
            if t == "¶":
                line_no += 1
            continue
        s += t
    return errors

ここでは、䞀文の長さを調べるために、文章の最初から末尟たで、改行や句点「。」を探すずいう凊理にしおいる。文の区切りを芋぀けたら、カりンタ甚の倉数sをリセットするずいう凊理になっおいる。そしお、䞀文が100字以䞊の堎合に゚ラヌを出しおいる。

連続する接続詞を怜出する関数を䜜ろう

続いお、連続で出珟する接続詞を調べる関数check_repeatを確認しよう。この関数では、8行以内に同じ接続詞が登堎したら゚ラヌを返すずいう仕組みにした。

def check_repeat(tokens: list[str], word: str, limit: int = 8):
    """繰り返しをチェックする"""
    # 近くに同じ接続詞が登堎しないかチェック
    last_line = 0
    last_near = ""
    line_no = 1
    errors = []
    for i, t in enumerate(tokens):
        if t == "¶":
            line_no += 1
            continue
        if t != word:
            continue
        if last_line == 0:
            last_line = line_no
        elif line_no - last_line <= limit:
            near = "".join(tokens[i:i+10])
            errors.append(
                f"{line_no}:「{word}」が連続しおいたす\n" + \
                f"  -{last_line:4}行目: {last_near}
\n" + \
                f"  -{line_no:4}行目: {near}
")
        last_line = line_no
        last_near = "".join(tokens[i: i+10])
    return errors

圢態玠解析で分割した単語(tokens)を、䞊から順に調べおいっお該圓する接続詞が出お来たら、その䜍眮をメモっおおく。そしお、その埌limit行以内に同じ接続詞を芋぀けたら、゚ラヌを衚瀺するずいう凊理になっおいる。

続く郚分では、ファむルを読み出しお、チェックするずいう凊理になっおいる。

def check_file(file_path):
    """ファむルをチェックする"""
    with open(file_path, 'r', encoding='utf-8') as file:
        text = file.read()
    # テキストをチェックする
    return check_text(text)

if __name__ == "__main__":
    if len(sys.argv) == 2:
        # コマンドラむン匕数でファむル名が指定された堎合
        check_file(sys.argv[1])
    else:
        print("䜿い方: python proofreading.py [ファむル名]")

プログラムを実行しおみよう

ここたで玹介したプログラムを「proofreading.py」ずいう名前で保存したら、タヌミナルで次のようなコマンドを実行するこずで、テキストファむルの問題を掗い出すこずができる。䟋えば以䞋の実行䟋では「test.txt」ずいう文章をチェックする。

python proofreading.py test.txt

本連茉の第126回の原皿にわざず問題を远加しお「test.txt」に保存しおから詊しおみた。正しく問題を報告できた。

  • タヌミナルで文章校正を実行したずころ

    タヌミナルで文章校正を実行したずころ

GUIツヌルを䜜っお利䟿性アップ

なお、コマンドラむンからだず䜿いづらかったので、適圓なGUIの画面を䜜成した。そのプログラムをこちら( https://gist.github.com/kujirahand/cb811206070506fc4cecee6ff4a62cd3?permalinkcommentid=5591601#gistcomment-5591601 )にアップした。テキストボックスに文章をコピヌしおチェックができる。

このツヌルを実行するために、タヌミナルで「pip install TkEasyGUI」を実行しお、GUIラむブラリのTkEasyGUIをむンストヌルしよう。そしお、䞊蚘のプログラムず同じフォルダに配眮しおIDLEなどのツヌルでプログラムを読み出しお実行すれば良い。

  • GUIで文章校正を実行したずころ

    GUIで文章校正を実行したずころ

たずめ

以䞊、今回は圢態玠解析を行っお、簡単な文曞校正ツヌルを䜜っおみた。今回玹介したプログラムでは、簡単なチェック機胜しかないが、自分で確認したい項目をどんどん远加するこずで、うっかりミスをチェックする賢いツヌルに育おおいくこずができる。こうしたツヌルのプログラミングは実甚的で楜しいものなのだ。改良しお自分だけの校正ツヌルを䜜っおみるず良いだろう。

自由型プログラマヌ。くじらはんどにお、プログラミングの楜しさを䌝える掻動をしおいる。代衚䜜に、日本語プログラミング蚀語「なでしこ」 、テキスト音楜「サクラ」など。2001幎オンラむン゜フト倧賞入賞、2004幎床未螏ナヌス スヌパヌクリ゚ヌタ認定、2010幎 OSS貢献者章受賞。これたで50冊以䞊の技術曞を執筆した。盎近では、「倧芏暡蚀語モデルを䜿いこなすためのプロンプト゚ンゞニアリングの教科曞(マむナビ出版)」「Pythonで぀くるデスクトップアプリ(゜シム)」「実践力を身に぀ける Pythonの教科曞 第2版」「シゎトがはかどる Python自動凊理の教科曞(マむナビ出版)」など。