Python Lab #5 ― 日本語解析 on GUI

# Python Lab #5 ― 日本語解析 on GUI

GUI で日文を入力したら MeCab を使って日本語を解析するという Python スクリプトを開発してみました。
そのうち、チャットボットを開発しようかな～。

## 開発に至った動機

MeCab というライブラリを使うと、日文を分かち書きしたり日文の品詞識別をしたりすることができることを知りました。過去に、日文の単語レベルの grep を作ってみたい（まずは名詞が探せればよい）と思ったことがあるので、MeCab を試してみることにしました。

**Google Colab で試した例（品詞識別）**

![PythonLab-MecabExecutor_0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/244edb2f-9bb6-5640-2720-fea7015a6b53.jpeg)

今後、何しらの開発をするのなら GUI 化できるようにしておいたほうが良いだろうと思い、GUI で MeCab 処理をラップすることにしました。GUI 部分は Flet を採用しました。

MeCab を使い始めるのには、たった数行のコーディングで済みました（注）。むしろ Flet のコーティングのほうに時間がかかりました。ただ、Flet も使いこなせるようになりたいので、それはそれでヨシとしましょう。

注）もちろん、本式にいろいろなことをやるなら難しいコーディングも必要となるでしょう。

## 実行イメージ

**GUI 起動時**

![PythonLab-MecabExecutor_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/44626e73-d486-0205-7ea1-fd4b682d30c9.jpeg)

**分かち書き**

![PythonLab-MecabExecutor_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/79babe85-2056-24c7-992f-4238ad1dd769.jpeg)

**品詞識別**

![PythonLab-MecabExecutor_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/bd7d59ec-ef44-de35-2101-3156ef3d9547.jpeg)

**日文未入力**

日文が未入力の場合、GUI 側でその旨を判定し、スナックバーでエラーを表示します。

![PythonLab-MecabExecutor_4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529613/929928b5-ba2f-1e70-43ac-983b487626db.jpeg)

## システム辞書のインストール

MeCab を使用する上で特殊な作業として、システム辞書をインストールする必要があります。

* 操作例。
    ```
    > python -m unidic download    
    ```

## ソースコードの簡単な説明

* mecab_executor.py。
    ```python:mecab_executor.py
    #!/usr/bin/env python3
    
    ・・・
    
    # Import Libraries
    import flet as ft
    import MeCab
    
    # Windows Size
    WINDOW_RATIO = 60
    WINDOW_WIDTH = 16 * WINDOW_RATIO
    WINDOW_HEIGHT = 10 * WINDOW_RATIO
    LIST_SPACING = 0
    LIST_PADDING = 5
    
    
    # Execute Mecab
    def execute_mecab(page: ft.Page, check_value: bool, text_value: str) -> None:
        compo_list = ft.ListView(expand=1, spacing=LIST_SPACING, padding=LIST_PADDING)
        page.add(ft.ResponsiveRow([compo_list]))
        if check_value:
            tagger = MeCab.Tagger()
            result = tagger.parse(text_value)
        else:
            wakati = MeCab.Tagger('-Owakati')
            result = wakati.parse(text_value)
        compo_list.controls.append(ft.Text(result))
        page.update()
        return
    
    
    # Main
    def main(page: ft.Page) -> None:
    
        def yes_click(e):  # noqa
            page.window_destroy()
    
        def no_click(e):  # noqa
            confirm_dialog.open = False
            page.update()
    
        confirm_dialog = ft.AlertDialog(
            modal=True,
            title=ft.Text('Confirm'),
            content=ft.Text('Are you sure?'),
            actions=[
                ft.ElevatedButton('Yes', on_click=yes_click),
                ft.OutlinedButton('No', on_click=no_click),
            ],
            actions_alignment=ft.MainAxisAlignment.END,
        )
    
        def window_event(e):
            if e.data == 'close':
                page.dialog = confirm_dialog
                confirm_dialog.open = True
                page.update()
                return
    
        def click_execute_button(e):  # noqa
            text_value = str(compo_text[len(compo_text) - 1].value).strip()
            check_value = compo_check_button.value
            if not len(text_value):
                page.snack_bar = ft.SnackBar(ft.Text('日文を入力してください。'), show_close_icon=True)
                page.snack_bar.open = True
                page.update()
                return
            compo_text[len(compo_text) - 1].read_only = True
            page.remove(compo_input)
            execute_mecab(page, check_value, '%s' % text_value)
            compo_text.append(
                ft.TextField(label='日文', hint_text="日文を入力してください。",
                             value='', text_align=ft.TextAlign.LEFT, autofocus=True)
            )
            page.add(ft.ResponsiveRow([compo_text[len(compo_text) - 1]]), compo_input)
            page.update()
            return
    
        def click_close_button(e):  # noqa
            page.window_destroy()
            return
    
        page.title = 'Mecab Executor'
        page.scroll = ft.ScrollMode.ALWAYS
        page.window_width = WINDOW_WIDTH
        page.window_height = WINDOW_HEIGHT
        page.window_prevent_close = True
        page.on_window_event = window_event
        page.add(ft.ResponsiveRow([ft.Text('[日文] テキストボックスに日文を入力し [実行] ボタンをクリックすると、MeCab を呼び出して、日文の分析結果を表示します。')]))
    
        compo_text = [
            ft.TextField(label='日文', hint_text="日文を入力してください。",
                         value='', text_align=ft.TextAlign.LEFT, autofocus=True)
        ]
        compo_execute_button = ft.FilledButton(text="実行", on_click=click_execute_button)
        compo_close_button = ft.OutlinedButton(text="閉じる", on_click=click_close_button)
        compo_check_button = ft.Checkbox(label="詳細表示", value=False)
        compo_input = ft.Row([compo_execute_button, compo_check_button, compo_close_button])
        page.add(ft.ResponsiveRow([compo_text[0]]), compo_input)
    
    
    # Goto Main
    ft.app(target=main)
    ```
    **execute_mecab()**
    MeCab ライブラリを呼び出す。
    **click_execute_button()**
    [実行] ボタンがクリックされたとき、テキストボックスから日文を取り出し、“execute_mecab()” を呼び出す。
    **main()**
    メイン処理。画面にテキストボックスや各種ボタンを設置したり、ボタンイベント “click_execute_button” を設定したりなどする。

## ソースコードの置き場所

https://github.com/tengbu-haoshou/Python_lab-mecab_executor

## 参考

**Google Colab で MeCab**

https://qiita.com/Ninagawa123/items/c90cccb453e2a6fc4466

**MeCab の品詞識別の内容**

https://qiita.com/qq8244353/items/ad567770bba80c717715

> 単語\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音

**MeCab、janome、sudachi**

https://qiita.com/paulxll/items/aaf2175119f2ad9cf9ac