形態素解析器を作るためにChaSen辞書の構造を読み解く

この記事は[Nextremer Advent Calendar 2018](https://qiita.com/advent-calendar/2018/nextremer)の3日目の記事です。
とても遅れた投稿になってしまいましたが3日目の記事です。

# 導入
先日、なぜか形態素解析器を作りたいと思い立ち、形態素解析器 茶筌(以後 ChaSen)の辞書を利用した形態素解析器を書きました。
モノは[これ](https://github.com/carrotflakes/muddler)ですが、これについて立ち入った話はしません。辞書の話です。
なぜChaSenを選んだのかというと、MeCabでも良かったのですが、MeCabよりChaSenのほうが日本語的に構造化されているように見えたからです。MeCabは謳い文句にあるように、言語非依存で、ひたすら形態素を並べたような感じの辞書になっています。
形態素解析器を作る上で辞書の構造が少し難しく、資料もろくに見つけられなかったのでここに書き残すことにしました。結果としてオレオレ解釈になっていることをご了承ください。

# 用語
## 形態素
文を構成する、意味を持つ文字列の最小単位です。
形態素解析の結果として形態素の配列を返すことが期待されます。

## 品詞
形態素を文法的な機能や形態などによって分類したものです。
ツリー状に体系化されており、例えば、`名詞` は `名詞-一般`、`名詞-固有名詞`、... などに細分類されます。
辞書ではS式で表現されており、例えば `(名詞 固有名詞 人名 性)` のように表現されます。
形態素は必ず1つの品詞を持ちます。

## 活用形
一般に、一部の単語は文脈によって末尾が変化します（活用すると言います）。その活用の種類を活用形と呼びます。
`基本形`、`未然形`、`連用形`、など。

## 活用型
同じような活用をする単語をまとめ上げ、それに付けた名前を活用型と呼びます。
例えば、「美しい」という単語の活用型は `形容詞・イ段` で、`形容詞・イ段` という活用型は `基本形`、`文語基本形`、`未然ヌ接続`、…などの活用形を持ちます。
形態素は活用型を持たないか、もしくは1つの活用型を持ちます。

(「活用型」の読みってなんなんですかね、「かつようがた」？「かつようけい」？調べても出てきませんでした。)

## 語幹
活用する単語の、活用しても変化のしない部分を語幹と呼びます。
「美しい」は「美しく」や「美しき」などに活用しますが、そのうちの `美し` の部分が語幹になります。

## 連接コスト
2つの連続した形態素のつながり難さ。
非負な整数。

## 生起コスト
形態素の出現のし難さ。
非負な整数。
(生起コストという名前はMeCabから拝借しましたが、ChaSenで同じように言うかどうかはわかりません)

# 辞書概要
こちらにあるChaSen用ipadic-2.7.0を対象にします。
https://ja.osdn.net/projects/ipadic/releases/

展開すると、ルートに53くらいのファイルがあるディレクトリになります。
そのうち注目すべきファイルはこれです。

```
*.dic
connect.cha
ctypes.cha
cforms.cha
grammar.cha
chasenrc
```

`*.dic` は形態素が列挙されている最も重要なファイル群です。
`connect.cha` には連接コストが記述されています。
`ctypes.cha` には品詞に対する活用型のリストが記述されています。
`cforms.cha` には活用型に対する活用形のリストが記述されています。
`grammar.cha` には品詞を細分化するツリーが記述されています。
`chasenrc` ChaSen の設定ファイルです。


上に列挙したファイルはすべてコメントを含むS式で書かれています。また、エンコードは `EUC-JP` になっています。

# `*.dic` ファイル
このようなファイルです。

``` Noun.adjv.dic
(品詞 (名詞 形容動詞語幹)) ((見出し語 (きらびやか 2763)) (読み キラビヤカ) (発音 キラビヤカ) )
(品詞 (名詞 形容動詞語幹)) ((見出し語 (史的 3114)) (読み シテキ) (発音 シテキ) )
(品詞 (名詞 形容動詞語幹)) ((見出し語 (プラトニック 3114)) (読み プラトニック) (発音 プラトニ \
ック) )
...
```

``` Adj.dic
(品詞 (形容詞 自立)) ((見出し語 (やぼったい 2979)) (読み ヤボッタイ) (発音 ヤボッタイ) (活用型\
 形容詞・アウオ段) )
(品詞 (形容詞 接尾)) ((見出し語 (くさい 442)) (読み クサイ) (発音 クサイ) (活用型 形容詞・アウ\
オ段) )
(品詞 (形容詞 自立)) ((見出し語 (もの凄まじい 2979)) (読み モノスサマジイ) (発音 モノスサマジ \
イ) (活用型 形容詞・イ段) )
...
```

一行が1形態素に対応しており、1形態素は2つのS式オブジェクトで記述されます（よく見ると `(品詞 ...)` と `((見出し語 ...) ...)` の部分で分かれています）。
1形態素は `品詞` `見出し語` `生起コスト` `読み` `発音` `活用型` の要素から成ることがわかります。
活用型はあったりなかったりします(名詞は活用しないのでないですね)。

見出し語と生起コストがペアになっていたりするのが謎です。

# `connect.cha` ファイル
連接コストを記述したファイルです。
連接コストを計算する際、2つの連続した形態素とマッチする行が選ばれてその連接コストが返されます。
中身はこちら:

``` connect.cha
(((((フィラー))) (((記号 読点)))) 0)
(((((助動詞) 形容詞・イ段 ガル接続)) (((名詞 接尾 特殊)))) 0)
(((((助動詞) 形容詞・イ段 体言接続)) (((名詞 一般)))) 0)
(((((助動詞) 五段・ラ行特殊 命令ｅ)) (((助動詞) 特殊・ダ))) 0)
...
(((((形容詞 非自立) * 連用テ接続)) (((動詞 自立) 一段))) 994)
...
(((((助詞 接続助詞) * * および)) (((名詞 一般)))) 0)
(((((助詞 終助詞) * * かい)) (((記号 括弧閉)))) 0)
...
```

一行が `((左形態素とマッチする部分 右形態素とマッチする部分) 連接コスト)` のようになっています。
`左形態素とマッチする部分` `右形態素とマッチする部分` は同じフォーマットに成ります。以下がそのフォーマットです。

```
((品詞 活用型 活用形 見出し語))
```

`品詞` に当たる部分は必ず存在し、`*.dic` で記述される品詞と対応するようになっています。
`活用型`、`活用形` は省略されている場合があります。省略されていなければ形態素とのマッチが試されます。`*` と記述されている場合は省略とみなします。
`見出し語` は省略されている場合があります。省略されていなければ形態素の見出し語とのマッチが試されます。

~~外側の括弧は必要なのでしょうか？このファイルのすべての行を見る限りは省略できるように見えるので意義を見出すことができませんでした~~

# `ctypes.cha` ファイル
品詞に対する活用型のリストが記述されています。

``` ctypes.cha
...
((動詞 非自立)
        (カ変・クル
         カ変・来ル
         サ変・スル
         一段
         一段・クレル
         一段・ル
         五段・カ行イ音便
         五段・カ行促音便
         五段・カ行促音便ユク
         五段・サ行
         五段・マ行
         五段・ラ行
         五段・ラ行特殊
         五段・ワ行ウ音便
         五段・ワ行促音便
         四段・ハ行
         下二・得
         下二・ア行
         一段・得ル)
)

((動詞 接尾)
         (一段
          五段・サ行
          五段・ラ行)
)
...
```

```
(品詞 (活用型 ...))
...
```

というフォーマットになっているようです。
特筆すべきところはありません。

# `cforms.cha` ファイル
活用型に対する活用形のリストが記述されています。

``` cforms.cha
...
(一段
    (   ; (語幹          *           )
     (基本形        る    ル    )
     (未然形        *           )
     (未然ウ接続    よ    ヨ    )
     (連用形        *           )
     (仮定形        れ    レ    )
     (命令ｙｏ      よ    ヨ    )
     (命令ｒｏ      ろ    ロ    )
     (仮定縮約１    りゃ  リャ)
     (体言接続特殊  ん    ン    ))
)
...
(四段・ハ行
    (   ; (語幹        *     )
     (基本形      ふ  フ  ウ)
     (未然形      は  ハ  ワ)
     (連用形      ひ  ヒ  イ)
     (仮定形      へ  ヘ  エ)
     (命令ｅ      へ  ヘ  エ))
)
...
```

```
(活用型 ((活用形 見出し語末尾 読み末尾 発音末尾) ...))
...
```

というフォーマットになっています。

`*.dic` に記載されている形態素はすべて基本形であり、活用を加味するためにはこのファイルの情報が必須です。
すべての活用型が基本形を持っています。

私は、形態素解析器の中で、形態素の `見出し語` から基本形の `見出し語末尾` を削除して、各活用形の `見出し語末尾` をくっつけて活用した形態素に展開するという処理を書きました。

# `grammar.cha`
品詞を細分化するツリーが記述されています。

``` grammar.cha
(名詞
    (一般)
    (固有名詞
        (一般)
        (人名
            (一般)
            (姓)
            (名))
        (組織)
        (地域
            (一般)
            (国)))
    (代名詞
        (一般)
        (縮約))
    (副詞可能)
    (サ変接続)
    (形容動詞語幹)
    (数)
    (非自立
        (一般)
        (副詞可能)
        (助動詞語幹)
        (形容動詞語幹))
    (特殊
        (助動詞語幹))
    (接尾
        (一般)
        (人名)
        (地域)
        (サ変接続)
        (助動詞語幹)
        (形容動詞語幹)
        (副詞可能)
        (助数詞)
        (特殊))  ;追加
    (接続詞的)
    (動詞非自立的)
    (引用文字列)
    (ナイ形容詞語幹))

(接頭詞
    (名詞接続)
    (動詞接続)
    (形容詞接続)
    (数接続))
...
```

このツリーから、 `(名詞 一般)` `(名詞 固有名詞 一般)` `(名詞 固有名詞 人名 一般)` `(名詞 固有名詞 人名 姓)` のように品詞が導出できます。
~~特に導出する必要はないのですが。~~

# chasenrc
ChaSen の設定ファイルです。

形態素解析器を書く上でそんなに重要なファイルでないと判断したため、説明できるほど解読していません。
未知語の品詞、未定義連接コスト、品詞コストなどが定義されており、まじめにChaSenクローンを作るなら必要そうでした。

# その他の知見
辞書はS式で記述されていましたが、 Common Lisp と互換があるわけではなく、独自にパーサを書くことになりました。
文法は特に複雑でなかったためパーサを書くのは難しくないです。`Onebyte.dic` のパースで少し手こずることになります(`\` によるエスケープとダブルクオートによる囲みがあるため)。
アトムはすべて文字列として解釈し、生起コストなどの数値である部分は後から数値にパースすればよいでしょう。

文頭、文末を表す形態素(のようなもの)が暗黙的に定義されているようです。
文頭の品詞は `(文頭)`、文末の品詞は `(文末)` になります。
なぜこれが必要かというと、文頭/文末に連接する形態素の連接コストを定義するためです。

形態素解析をする上で必要なファイルは、実は `*.dic` `connect.cha` `cforms.cha` `chasenrc`
だけです(少なくとも自分で実装した限りは)。`ctypes.cha` `grammar.cha` は不要でした。

ChaSen の未知語処理の仕方が調べてもわかりませんでした。
(拙作の形態素解析器では、モチベーションの都合で未知語処理を実装していません。)