[cocoa][swift]形態素解析

<p><a href="https://yamakawa.etcetc.jp/">「私」物語化計画</a>という作家を育てるオンラインサロンに参加しているのだが、プログラマとして貢献できる方法として、執筆に役立つアプリケーションの開発に取り組んでみたいと考えている。その第一歩として、同一文章中に出てくる単語の個数を気にしているという話を聞いたので、テキストから文法情報を抽出する方法を調べたので発表する。</p>

<p>macOSで利用できる形態素解析 (Morphological Analysis) の機能は複数存在する。それは、それが実装された時期に利用できた機能などと関係があるからだと思う。</p>

# NSLinguisticTagger
iOS 5.0+
macOS 10.7+
<p>文章を品詞や属性で区分するクラス。ただし、日本語の場合、品詞には対応していないようだ。</p>

# NSOrthography
iOS 4.0+
macOS 10.6+
<p>スペルチェックや文法チェックで利用されることを目的としたクラスのようだ。</p>

# CFStringTokenizer
iOS 3.0+
macOS 10.5+
<p>以前、発表したことがあるAPIだ。当時は、問題がないAPIだったが頭にCFという言葉が付いているように、以前のCoreFoundation + Cocoa、つなり、NSString時代だと思われ、SwiftのStringとは合っていない部分があると思う。</p>

# NSString enumerateSubstringsInRange
iOS 4.0+
macOS 10.6+
<p>文字列を形態素解析と品詞分解するAPIだが、NSStringのメソッドということで、SwiftのStringとは合っていない部分があると思う。</p>

<p>今回の用途では、NSLinguisticTaggerが合っているのではと考えてサンプルコードを作ってみた。</p>

<pre><code>let text = "東京は、哀しい活気を呈していた、とさいしょの書き出しの一行に書きしるすというような事になるのではあるまいか、と思って東京に舞い戻って来たのに、私の眼には、何の事も無い相変らずの「東京生活」のごとくに映った。"
let linguisticTagger = NSLinguisticTagger(tagSchemes: NSLinguisticTagger.availableTagSchemes(forLanguage: "ja"), options: 0)
linguisticTagger.string = text
linguisticTagger.enumerateTags(in: NSRange(location: 0, length: text.count),
                     scheme: NSLinguisticTagScheme.tokenType,
                     options: [.omitWhitespace]) {
                        tag, tokenRange, sentenceRange, stop in
                        let subString = (text as NSString).substring(with: tokenRange)
                        print("\(subString) : \(String(describing: tag))")
}
</code></pre>

以下が、その結果。

<pre><code>東京 : Optional(__C.NSLinguisticTag(_rawValue: Word))
は : Optional(__C.NSLinguisticTag(_rawValue: Word))
、 : Optional(__C.NSLinguisticTag(_rawValue: Punctuation))
哀しい : Optional(__C.NSLinguisticTag(_rawValue: Word))
活気 : Optional(__C.NSLinguisticTag(_rawValue: Word))
を : Optional(__C.NSLinguisticTag(_rawValue: Word))
呈し : Optional(__C.NSLinguisticTag(_rawValue: Word))
て : Optional(__C.NSLinguisticTag(_rawValue: Word))
い : Optional(__C.NSLinguisticTag(_rawValue: Word))
た : Optional(__C.NSLinguisticTag(_rawValue: Word))
、 : Optional(__C.NSLinguisticTag(_rawValue: Punctuation))
・・・（略）・・・
「 : Optional(__C.NSLinguisticTag(_rawValue: Punctuation))
東京 : Optional(__C.NSLinguisticTag(_rawValue: Word))
生活 : Optional(__C.NSLinguisticTag(_rawValue: Word))
」 : Optional(__C.NSLinguisticTag(_rawValue: Punctuation))
の : Optional(__C.NSLinguisticTag(_rawValue: Word))
ごとく : Optional(__C.NSLinguisticTag(_rawValue: Word))
に : Optional(__C.NSLinguisticTag(_rawValue: Word))
映っ : Optional(__C.NSLinguisticTag(_rawValue: Word))
た : Optional(__C.NSLinguisticTag(_rawValue: Word))
。 : Optional(__C.NSLinguisticTag(_rawValue: Punctuation))
</code></pre>

<p>今後は、これをテキストエディターに組み込んでみたい。</p>

ソースコード
GitHubからどうぞ。<br />
<a href="https://github.com/murakami/workbook/tree/master/mac/MorphologicalAnalysis">https://github.com/murakami/workbook/tree/master/mac/MorphologicalAnalysis</a> - GitHub<br />

【関連情報】
<a href="https://cocoa-kanto.connpass.com/event/124467/">Cocoa.swift 2019-04</a><br />
<a href="https://cocoa-kanto.connpass.com/">Cocoa.swift</a><br />
<a href="https://www.facebook.com/groups/cocoa.kanto/">Cocoa勉強会 関東</a><br />
<a href="https://mosa.connpass.com/">MOSA</a><br />
<a href="http://www.bitz.co.jp/weblog/">Cocoa練習帳</a><br />
<a href="https://qiita.com/m_yukio">Qiita</a><br />