日本語の読み仮名を取得するには?[UWPアプリ開発]:WinRT/Metro TIPS
Windowsランタイムには形態素解析と呼ばれる手法を用いて日本語の読み仮名を取得する方法を解説する。
powered by Insider.NET
対象:Windows 8.1、Windows 10(デスクトップのみ)
日本語の読み仮名を取得したいと思ったことはないだろうか? 例えば、ファイル名を五十音順に並べたいような場合だ。デスクトップ用のユニバーサルWindowsプラットフォーム用のアプリ(以降、UWPアプリ)では、それが簡単に実現できるのだ。本稿では、「形態素解析」(後述)のAPIを使って日本語の読み仮名を取得する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #118」からダウンロードできる。
事前準備
Windows 10デスクトップ用のUWPアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Community 2015(およびVisual Studio Tools for Universal Windows Appsバージョン1.1)を使っている。
- Windows 10*1
- Visual Studio 2015(以降、VS 2015)*2
- Windows SDK for Windows 10*3、およびVisual Studio Tools for Universal Windows Apps*4
*1 デスクトップPC用のエディション(Home/Pro/Enterprise/Education)。開発に使うWindows 10は「開発者モード」を有効にしておくこと(「設定アプリ」の[更新とセキュリティ]−[開発者向け]で、[開発者モード]ラジオボタンを選択)。そうしないと、VS 2015のXAMLエディターがエラーになる。また、本稿の内容が適用できるのは、Windowsのライフサイクル管理の上では「Windows 10, released in July 2015」と呼ばれるリリース、またはそれ以降。WinVerコマンドで表示されるバージョンは「10.0 (ビルド 10240)」。UWPアプリ開発におけるデバイスファミリーのバージョン指定としては「10.0.0.0」(Package.appxmanifestファイルのTargetDeviceFamily)である。
*2 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2015 for Windows 10(製品版)はマイクロソフトのページから無償で入手できる(ページの左側で[Visual Studio 2015]−[Express 2015 for Windows 10]と選ぶ)。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、UWPアプリの開発には「for Windows 10」を使う(「for Desktop」はWPF/Windowsフォーム/Win32 APIのアプリ開発用)。また、Visual Studio Community 2015(製品版)もマイクロソフトのページから無償で入手できる。なお、英語版がインストールされた場合には、Microsoft Visual Studio 2015 Language Packの日本語版を追加インストールし、[オプション]ダイアログで言語を切り替える。
*3 使用しているVS 2015に含まれていない場合は、Windows SDK for Windows 10のページからダウンロードできる。ただし、プレビュー版のSDKを使うと、Windowsストアには提出できなくなるので注意してほしい。
*4 Visual Studio Tools for Universal Windows Appsは、2015年9月16日付でバージョン1.1に上がっている。それ以前に開発環境を整えた人は、個別にアップデートする必要がある。「Update 1.1: Release Notes and Installation Instructions」(英語)を参照。
形態素解析とは?
形態素(morpheme)とは言語学の用語で、意味を持つ言葉の最小単位のこと。文章を形態素に分解して調べることを形態素解析という。
形態素解析は、かな漢字変換に必須の技術といってよい。そのため、Windowsには以前から形態素解析を行うためのCOM APIが存在している(IFELanguage::GetJMorphResult)。
そして、Windows 8.1からWindowsランタイムで形態素解析が利用できるようになった*5。Windows.Globalization名前空間のJapanesePhoneticAnalyzerクラスである(音声読み上げに使うことが念頭にあったのであろうか、形態素ではなくphonetic=「表音の」という名前になっている)。
JapanesePhoneticAnalyzerクラスでは、かな漢字交じりの文字列から読み仮名を得ることだけができる(かなから漢字に変換することはできない)。なお、利用できるのはWindows 8.1とWindows 10のデスクトップのみである。
*5 なお、.NET Framework 2.0/3.5用として「Microsoft Visual Studio International Feature Pack」が提供されていた(現在はサポートされていないようである)。
日本語の読み仮名を取得するには?
JapanesePhoneticAnalyzerクラスのGetWordsメソッドを使う。引数に文字列を渡して呼び出すだけだ。返値は、JapanesePhonemeオブジェクト*6(Windows.Globalization名前空間)のコレクションである。JapanesePhonemeオブジェクトは分解された形態素を表しており、次の三つのプロパティを持っている。
- DisplayTextプロパティ: 入力された文字列を分解したもの
- YomiTextプロパティ: 読み仮名
- IsPhraseStartプロパティ: 句の先頭であるときtrue
なお、GetWordsメソッドに渡せる文字列には100文字未満という制限があるようだ。MSDNドキュメントに記載はないが、100文字になると何も返ってこなくなる。
*6 ここでも「phoneme」(音素)と、音声読み上げを想定しているような名前が付けられている。
具体的な処理を行うコードは、次のコードのようなものになるだろう。
private void SampleMethod(string text, bool monoRuby = false)
{
// JapanesePhoneticAnalyzerはデスクトップ専用APIなのでチェックする
// ※Windows 8.1ではチェック不要
if (!Windows.Foundation.Metadata.ApiInformation.IsTypePresent(
"Windows.Globalization.JapanesePhoneticAnalyzer"))
return;
// JapanesePhoneticAnalyzerクラスのGetWordsメソッドを呼び出すだけで、
// 形態素への分割と、読み仮名の付与をしてくれる
IReadOnlyList<Windows.Globalization.JapanesePhoneme> list
= Windows.Globalization.JapanesePhoneticAnalyzer
.GetWords(text, monoRuby);
// 全体の読み仮名を取得する例
string yomi
= string.Join(string.Empty, list.Select(p => p.YomiText));
// 形態素ごとの処理をする例
foreach (var phoneme in list)
{
// 分割した文字列(形態素)
string displayText = phoneme.DisplayText;
// 分割した文字列の読み仮名
string yomiText = phoneme.YomiText;
// この形態素は句の先頭か?
bool isPhraseStart = phoneme.IsPhraseStart;
// 形態素ごとに何か処理をする
……省略……
}
}
Private Sub SampleMethod(text As String, Optional monoRuby As Boolean = False)
' JapanesePhoneticAnalyzerはデスクトップ専用APIなのでチェックする
' ※Windows 8.1ではチェック不要
If (Not Windows.Foundation.Metadata.ApiInformation _
.IsTypePresent("Windows.Globalization.JapanesePhoneticAnalyzer")) Then
Return
End If
' JapanesePhoneticAnalyzerクラスのGetWordsメソッドを呼び出すだけで、
' 形態素への分割と、読み仮名の付与をしてくれる
Dim list As IReadOnlyList(Of Windows.Globalization.JapanesePhoneme) _
= Windows.Globalization.JapanesePhoneticAnalyzer _
.GetWords(text, monoRuby)
' 全体の読み仮名を取得する例
Dim yomi As String _
= String.Join(Nothing, list.Select(Function(p) p.YomiText))
' 形態素ごとの処理をする例
For Each phoneme In list
' 分割した文字列(形態素)
Dim displayText As String = phoneme.DisplayText
' 分割した文字列の読み仮名
Dim yomiText As String = phoneme.YomiText
' この形態素は句の先頭か?
Dim isPhraseStart As Boolean = phoneme.IsPhraseStart
' 形態素ごとに何か処理をする
……省略……
Next
End Sub
このコードは、Windows 10のUWPアプリ用に書いてある。Windows 8.1では、冒頭のチェックは不要である。また、Windows 10のUWPアプリでは、プロジェクトに[Windows Desktop Extensions for the UWP]への参照を追加する必要がある。
このメソッドの第2引数「monoRuby」は、形態素解析の手法を切り替える(その効果は後述する)。
形態素に分解された結果とはどのようなものか、紹介しておこう。まず、GetWordsメソッドの第2引数「monoRuby」にfalse(=既定値)を指定して、文字列「読みを取得する」を与えた場合(次の表)。
list[0] | list[1] | list[2] | list[3] | |
---|---|---|---|---|
DisplayTextプロパティ | 読み | を | 取得 | する |
YomiTextプロパティ | よみ | を | しゅとく | する |
IsPhraseStartプロパティ | true | false | true | false |
GetWordsメソッドの第1引数には「読みを取得する」という文字列を、第2引数にはfalseを与えた場合。返値を格納した「list」変数の内容は、このようになる。
次に、第2引数「monoRuby」にtrueを指定し、文字列「明日の天気」を渡した場合(次の表)。
list[0] | list[1] | list[2] | list[3] | |
---|---|---|---|---|
DisplayTextプロパティ | 明日 | の | 天 | 気 |
YomiTextプロパティ | あした | の | てん | き |
IsPhraseStartプロパティ | true | false | true | false |
GetWordsメソッドの第1引数には「明日の天気」という文字列を、第2引数にはtrueを与えた場合。返値を格納した「list」変数は、このようになる。
monoRubyオプションをtrueにすると、可能な限り細分化される(「天気」が「天」と「気」にまで分解されている)。ただし、「明日(あした)」のように、文字単位まで分解できないものもある。
このように、monoRubyオプションをtrueにすると、可能な限り細かく分割してくれるのである。用途に応じて使い分けてほしい。
サンプルの実行結果
別途公開のサンプルでは、以上の動作を確認できるようにしてある(次の画像)。
形態素ごとの処理をする例として、ルビ(フリガナ)を付ける簡易的な処理を行っている(前出のサンプルコードで「形態素ごとに何か処理をする」とコメントしてある部分で処理している)。得られたJapanesePhonemeオブジェクトを調べて、DisplayTextプロパティとYomiTextプロパティが異なっているときだけ、本来の文字の上側にYomiTextプロパティの文字列を小さいフォントで表示しているのだ。
また、monoRubyオプションの効果も確かめられるようにしてある。JapanesePhoneticAnalyzerクラスの動作確認用としてご利用いただければ幸いである。
別途公開のサンプルの実行結果(Windows 10デスクトップ)
JapanesePhoneticAnalyzerクラスのGetWordsメソッドは、記号類の一部にも読み仮名を付けてくれるお茶目なAPIである。青い文字列の上には、前述した手法でルビを付けた。また、青い文字列の下には、形態素の左端の位置に赤と緑の印を表示してある。赤はIsPhraseStartプロパティがtrue(=句の先頭)、緑はfalse(=句の先頭ではない)である。
上:monoRuby=falseの場合。漢字は熟語ごとに分割されるようだ(「明日」/「天気」)。送り仮名も含めて一つの形態素とされる(「恵まれ」など)。
下:monoRuby=trueの場合。できるだけ細かく分割される。基本的には1文字単位に分割されるようだ。ただし、「明日」(あした)はこれ以上分割できないので、残されている。なお、monoRubyオプションによって句の区切り位置(赤色の印)は変化しない。
まとめ
かな漢字交じりの文字列から読み仮名を取得するのは、意外と簡単だ。ただし、入力できる文字列に長さ制限がある(100文字未満のようだ)。また、必ず正しい読み仮名を付けてくれるわけではない。
Copyright© Digital Advantage Corp. All Rights Reserved.