JPを触っていたら、付属の音声合成eSpeakに日本語がないのはとても残念だと思った。NVDAのポータブル版にそれが入っていれば、USBメモリを差せばどのWindowsXPも、音声パソコンにすることができるから。いうわけで、いろいろ調べてみた。結局まだできないのだけど、ちょっと面白いものができたので、公開してみることにする。eSpeakを調べていると、MBROLAという音声合成のプロジェクトを見つけた。世界中の音声が用意されていて、これで使える日本語音声も三種類公開されている。MBROLAのプログラムに音素で表記された文章を与えると、それを音声として読み上げてくれる。いうことで、漢字仮名交じりの日本語をこれで使える音素に分解するスクリプトを作ってみることにした。V0.2という名前で公開されていた。これはRubyというプログラミング言語で記述されていて、OSはlinux向けに書かれていた。これはとてもよくできていて、日本語の文書を渡すとその通りに発音してくれる。抑揚はつけていないので、棒読みになる。これをNVDAでも使えるようにと思って、NVDAを記述しているPythonというプログラミング言語で書き直してみた。結局まだどう組み込めばいいのかもわからないので、まだまだNVDA対応などではないけれど、とりあえず漢字仮名交じり文を音素に分解できるようになった。出力されるファイルをMBROLAのプレイヤーで開くとちゃんと棒読みで喋ってくれる。muDaTTSは数字の羅列をちゃんと日本語の数として読んでくれる。この再現にはかなり手こずったが、なんとかこちらでも読めるようになった。基本的な部分はRubyからPythonへの翻訳なので原形をとどめているところもあれば、こんなふうにかなり変更してあるところもある。muDaTTSはアルファベットが読めなかったので、変換辞書を作って対応してみた。単語の日本語での読み方が用意してあればそれで読み、単語が分からないときは綴りを読むようにした。この辞書へは英単語以外も登録できる。muDaTTSでは、漢字から仮名への変換にChaSenというソフトを使っていたが、後発のmeCabというソフトを使ってみたかったので、そちらを使うように書きかえた。kakasiというプログラムを仮名からローマ字への変換に使っていたが、ここのアルゴリズムを考えるのは面白そうだったので仮名文字から直接音素記号をはき出すように自分で書いてみた。最終的にはこのスクリプトだけで、しゃべり出してくれることを目的としているけれど、まだMBROLAの扱い方が分からないので、今のところは日本語テキストを標準入力に与えると、音素に分解したテキストファイルを標準出力に吐きだすようになっている。ここで使われている音素の記号は後述するJP2で使われているものである。名前はPyDaTTSとしてみた。ダウンロードは次のリンクからできる。WindowsXPのみ対象。PyDaTTS.zip解凍するといろんなファイルが出てくる。スクリプトやバッチファイルもファイルの内容を理解してから実行してください。自己責任でご利用ください。ウィルス検査してからUPしてあります。念のため確認してください。これを動かすためには、四つのソフトがインストールされている必要がある。MBROLA用日本語音声JP2それぞれ以下のサイトのダウンロードページからダウンロードする。リンク先にインストールの指示もあると思うので、それにしたがって入れていけばいい。ProjectMBROLAのダウンロードページの下の方にJP2も用意されている。JP2を解凍したものをMBROLAがインストールされた場所にコピーする。コピーした中の付属のphoファイルをダウンロードすると、音声登録の指示が出るので、それにしたがって登録すればいい。漢字→かな(ローマ字)変換プログラムはっきりいって、これはまだプログラムの分からない人には扱えない。これが一般の人向けに利用できるようになるのはまだ当分先だろう。それを作るのは僕である必要もない。バッチファイルを入れてあるので、「text.txt」に適当な文章を書いて、play.batをダブルクリックすれば、標準的なMBROLAのインストールをしていれば、そしてJP2という日本語音声を入れてあれば、たぶんしゃべり出してくれる。パラメータをいじるとJP2のサンプルのようにそれなりに抑揚もつけられるのだけど、その数値の意味をまだ理解していないし、たぶん難しいので、棒読み。今回作ったサンプル音声は以下のリンクから聞くことができる。・平成17年10月1日に調査された日本の総人口は、127,767,994人です。|2007年12月12日WindowsのPython用MeCabパッケージを作って、それに対応してみた。前回の日本語を音素に分解するスクリプトの公開で、Ctypesを利用してMeCabを操作していたのは、Python用MeCabモジュールのWindows版作れなかったから。公式モジュールがあるのだから今回はこれを使えるようにしてみた。普通に、MeCabサイトからPython用のバインドモジュールをダウンロードできるが、インストールしようとするとコンパイラとしてVC++2003を要求されてしまう。物持ちがよくて現役を退いたVC++2003を用意できたとしても、今度はコンパイルエラーが出てしまう。理由を調べてみると、「MeCabのPythonバインディングをWindowsでビルド」に書いてあった。MeCab.hを次の差分のように書き換えなくてはいけない。上記のリンク先の変更とは多少違う。*/MeCabサイトに行ってソースを持ってきて解凍し、srcフォルダに入っているMeCab.hを上記のように書き換え、SWIGを使ってmecab_wrap.cxxを作り直す。SWIGというのは、バインドのためのコードを自動で作ってくれるソフト。MeCabの公式のPythonバインドもこれを使って生成されている。SWIGサイトからWindows版を持ってきてインストールするmecabソースのswigフォルダで下記のようなコマンドを実行すると、i拡張子のファイルの指示に従って、仲介するコードを作ってくれる。mecab.iなおこのswig.exeにはPATHは通っている。以後上記のようなコマンドの例は適切にPATHなどの環境変数が設定されているとする。(2006/01/15)」を参考にして、setup.pyも修正する。Files/MeCab/sdk」にインストールされているとすると、次のようになる。libraries=['libmecab'])])このフォルダで次のコマンドを実行するとセットアップが完了する(VC++2003を持っていれば)。installさて、VC++2003(VC7.1)が要求されるのはどうしてだろう。それはWindows向けのPython2.5がVC++2003でコンパイルされて作られたプログラムだからだ。詳しく言うとPython2.5がMSVCR71.DLLを使っているから。Windowsではコンパイラの種類によって、それで作ったプログラムの使うMSVCRTの種類が違ってくる。その違うMSVCRTを一つのプログラムの中で使おうとすると、ランタイムエラーでプログラムが止まってしまう。Pythonのセットアップスクリプトは、Python本体を作るときに利用したのと同じVC++2003を要求して、モジュールでも同じMSVCR71.DLLを使おうとする。VC++2003を持っていると、とりあえず上記の改造されたMeCab.hを使って作ったmecab_wrap.cxxをsetup.pyでコンパイルしインストールができる。持っていない人はどうすればコンパイルできるだろうか。残念ながらVC++2003は販売終了している。2003というコンパイラがある。これは数年前までマイクロソフトから無料で配布されていたコンパイラだ。SDKをインストールして使う。Compiler参照)すれば、パッケージを作ってくれる。残念ながらこのVC++ToolKit2003も配布は終了している。いうわけで現在ではMSVCRT7.1を使うマイクロソフト純正コンパイラは入手困難となっている。それでも、どうしても入手しなくてはいけないのならば、マイクロソフト社のMSDNに入会することになるだろう。タイムリーにもMSDNへは現在VC++2008発売直前のキャンペーンで少し安く入会できる。早期導入キャンペーン。一つ、特定のバージョンを以前買ったことがある人へのキャンペーンも実施されている。〜今なら更新パッケージがお得!〜。どちらにしても、仕事で使わない限り、手軽に買える商品ではないので、これは万人の解決法ではない。するかというと、MSVCR71.DLLを使うことを諦めて現在入手可能なコンパイラを使ってMSVCRTそのものを使わないモジュールを作ればいい。その組み合わせで問題が起きないかはやってみないと分からないが。日本語版(VC8)は登録が必要だが無料で入手できる。SDKをインストールして使う。このコンパイラでも上で作り直したmecab_wrap.cxxをそのままコンパイルすることができる。そのときコンパイラのスイッチとして、/MDではなく/LDを使う(/MTでも良さそうだが今回/MTで動かなかった)。/LDだとMSVCRTを使わないDLLを作る。"C:\Python25\libs\python25.lib"長いので折り曲げて書いてあるが上記を一行で書く。環境変数path、include、libが適切に設定されているとする。上記「MeCabのPythonバインディングをWindowsでビルド」にあるものと同じコード。誰かがコンパイルしたものを配ってくれれば個々にこんな面倒なことをしなくてもいい。それもMSVCR71.dllに対応したコンパイル済みのモジュールを。MeCabの配布先でついでに公開してもらえると楽なんだけどまだそれはない。調べてみると、setup.pyスクリプトでモジュールのインストールができると、ほんの少しのコマンドラインの変更で配布用パッケージも作ることができるのが分かった。pyhtonにはこのようにパッケージを作る機能も備わっている。いろんな所で見かけたpythonの配布パッケージもそうやって作っていたのかと今回初めて知った。書いてきたけれど、そういうわけで、setup.pyを使って作ってみた。pyDaTTL06.zip上記のプログラムを利用するためには、libmecab.dllへPATHが通っていないといけない。Files/Mecab/bin"にあるlibmecab.dllを確実にPATHが通っている"C:/WINDOWS/SYSTEM32/"に放り込めばいい。MeCabを使っていろいろ試してみるにはこのbinフォルダにある他のコマンドが自由に使えた方が楽なので、今後のためにこのbinフォルダをPATHに追加しておいてもいい。前回は、Windows向けPython2.5で使われているのはmsvcr71.dllだということ。現在で回っているマイクロソフト製のコンパイラでは、もう世代が変わってしまっていて、そのmsvcr71.dllにリンクするプログラムを作るのはとても大変だということを書いた。マイクロソフト製以外にもコンパイラはある。GCCを使ってもコンパイルできる。これを使うとmsvcr71にリンクするプログラムを作ることができる。GCCでlibcとしてmsvcrt.dll以外を使うまとめ」で詳しくまとめられている。GCCは標準でmsvcr71.dllではなく、msvcrt.dllへリンクするように作られているので、ちょっと工夫しないといけない。その工夫の仕方が書いてある。記事の最後の方の「もっと根本的に、specファイルを書き換える方法」で紹介されているspecファイルを書き換えたものを用意して、それをコンパイル時に-specで指定する方法が、一番無難な方法じゃないかと思う。常にmsvcr71.dllへリンクしたものを作るというのならば、「C:/MinGW/lib/gcc/mingw32/3.4.5/(バージョン番号は適宜置き換え)」にあるspecsファイル中の-lmsvcrtを-lmsvcr71に置き換えてしまえば、煩わしくなくなるだろう。ためしにmecabソースをその設定でビルドしてみるとctype.hの記述が原因でエラー終了してしまった。すべてがうまくいくというわけでもないみたい。GCCではVCとはまた別のライブラリを用意しないといけない。VCのライブラリからの変換の手順はいろんなところで紹介されているので、それにしたがって作ればいい。そもそもMinGW環境そのものの構築の仕方は、面倒なので書いていないが、これも検索すれば見つかる。|2007年12月17日MeCabで日本語インタプリタMeCabで日本語の構文を自由に解析できるようになったので、それを使って、日本語計算機を作ってみることにした。現在まだ最低限のことができるようになっただけなんだけど、しばらくこれを作っていこうかと思う。これを少しずつ拡張していけば、日本語のプログラミング言語処理系にできるかもしれない。5年くらい前にプログラミング言語のロゴを日本語化していた。日本語の構文解析の部分で挫折してしまった。chasenやMeCabを使えばいいんだろうなということは、あとで分かってきたけれど、なかなか手を出せないまま今に至ってしまった。それが、最近MeCabをPythonで使ってみて簡単に日本語が解析できてしまったので、これはいけると思ってしまった。それで作ってみることにした。開発言語としては今のところPythonを使ってみる。インタプリタをインタプリタで作るというのは、ちょっと速度的にもったいなさそうだけど、Pythonの気軽なプロトタイピングが今かなり気に入っているので、とりあえずこれで作る。日本語プログラミング言語というのは古くはMindというものから、現在「なでしこ」「ドリトル」「プロデル」などが出てる。今でも販売されているMindはForthというもともと英単語を後置表記で表記していたプログラミング言語を日本語の単語で使えるようにすることから始まっている。一方の現在主流の日本語プログラミング言語は、ソースを読んで確認したわけではないけれど、どうやらロゴを発展させた形で作られているのではないかと思う。根拠は、以前日本語ロゴを作った経験から。ドリトルの前身はロゴ坊というまさに日本語ロゴだったし、後継ドリトルでも、タートルグラフィックが得意だったりしている。プロデルのプログラムの外見もまさにロゴを日本語語順になおしたものに見える。いう先人がいるのだけれど、おそらくそれらを追い越せるだけのものが簡単に作れるとも思わないが、ちょっとアイデアがいろいろ思いつくので、日本語インタプリタを作ってみることにする。それもロゴを手本に作ってみる。MeCabという本格的な日本語解析モジュールを利用するのだから、かなりきっちりとした日本語表記を目指そうと思う。ダウンロードして試してもらう段階ではないけれど、公開しておきます。・MeCab公式サイトよりMeCabのWindows版をインストールしていること・Windows版Python2.5をインストールしてあること・Windows版Python2.5用MeCabモジュールをインストールしてあることpy2exeで実行形式にしたものの圧縮ファイルを置いたつもりが、UPしてませんでした。現時点では最低限のことしかできない。・解釈できるのは一行、それも単文。・整数の四則演算ができる。・上記の○、□の場所に数字を入れた文を書いて、エンターを押すと、次の行に答えが出てくる。・終了と入力すると終了する。やることは思いつくけど、まずリスト演算と再帰的な文の呼び出しを実現できるようにしよう。○と□には数値リテラルしか指定できない。これができれば十分複雑なことができるようになる。日本語プログラミング言語の仕様を考えてみる前回作ってみたものをどう発展させようか。以前から考えていたものをまとめてみた。できる限り細かく考えてみたが、整合性がとれるかどうか作ってみないと分からないし、それをプログラムできるかどうか分からない。考えていることを言葉で表すとこんな感じになる。文字:・プログラムの表記を構成する最小単位は文字である。・文字のコードは16ビットユニコードである。・エスケープコードによって表現されたものも一つの文字である。・空白、タブ、改行も文字である。・空白文字とは空白、タブ、改行である。・空白文字をエスケープコードで表現したものは空白文字とは見なされない。・空白文字の連続は一つの空白として扱われる。・空白は空白文字以外の文字の連続を分割する。記号:・記号は一つの文字もしくは複数の文字の連続によって表され、それを構成する文字の列があらかじめ複数定義されている。・記号は定義されているものの中で最も長いものとしてのみ解釈される。・記号とそれに隣接する文字や記号とは間に空白が無くても分割されている。数値:・先頭から末尾までの文字が数値を表すものとして解釈されるもののみが数値である。・数値には整数と実数がある。・整数は小数点を含まない。ワード(単語):・分割されていない文字の一つ以上の連続をワードと呼ぶ。・ワードには属性がある。・記号は記号という属性をもったワードである。・整数を表す文字の連続からなるワードは整数という属性をもつ。・実数を表す文字の連続からなるワードは実数という属性を持つ。・同一の引用符記号(”’"')に囲まれた文字の連続は、文字列という属性を持つワードである。・文字列には空白も含めることができる。・ワードには、言語仕様であらかじめ用意された手順によって値や手順を割り当てることができる。・ワードに値を割り当てるということは、値を返す手順を割り当てることである。・ワードは最初それ自身の文字の連続を値として返す手順が割り当てられている。・数値は常にそれが表す数値を値として持つ。・文字列は常にそれを構成する文字の並びを値として持つ。ノード:・ノードとはワードとリストをまとめて呼ぶための名前である。・ワードはワードという属性を持ったノードと考えることもできる。・リストはリストという属性を持ったノードと考えることもできる。リスト:・リストはノードによって構成される。・そのリストを構成するノードを要素と呼ぶ。・リストは別のリストの要素となるとき、対になるリスト引用符(「」[])で囲まれる。プログラム:・プログラムはリストである。・リストの最初の要素から順に各要素が消費され、実行されていく。■プログラムの解釈について・プログラムは文の並びである。・文は並んでいる順序で解釈される。・文には単純文と式文がある。・単純文はいくつかの目的語と述語からなる。)は文を区切る記号であり、それを越えて目的語の探索をしない。・読点(、)は単なるワードを区切る記号である。・述語には手順が割り当てられて、それに従って解釈される。・述語は解釈され値を返すものと値を返さないものがある。・値を返す述語は必ず値を返す。・値を返さない述語は必ず値を返さない。・述語の名前はそれを構成する文字そのものである。・目的語を持たない単純文もある。・後置詞は述語とともに定義される。・述語は後置詞によって目的語の値を受け取り、手順の処理で利用する。・目的語には後置詞が続いている。・目的語と後置詞は連結されていてもよい。・目的語と後置詞の間には空白文字があってもよい。・後置詞を伴わない目的語も許される。・後置詞の並びには順序がある。・同じ名前の述語でも違う後置詞を伴う場合は別のものとみなされる。・同じ名前の述語で同じ後置詞を伴う場合でも後置詞の順序が違うものは別のものとみなされる。・目的語の解釈は、述語の解釈に先立っておこなわれる。・値を返さない目的語があれば、その単純文の解釈は中止され例外が発生する。・目的語となれるものでもっとも単純なものは、目的語を持たない述語である。・一つの文章に多くの述語が使われ、目的語の所属の判断が複雑になる場合は、括弧「()()」を使って優先順位を明確にする。・目的語の探索は再帰的に右側の目的語から決定されていく。・式文は式によって記述された文であり、必ず値を返す。・式には単項式と二項式、そしてリスト式がある。・単項式は単項演算子と項からなり、値を返す。・二項式は項と二項演算子と項からなり、値を返す。・演算子には結合順位と結合方向があり、それに従って解釈される。・演算子は言語仕様に含まれ、新たに定義することはできない。・演算子は記号であるものと記号でないものがある。・演算子の項の属性が、演算子が要求するものではないときは例外が発生し、解釈が中止される。・項は、より結合順位の高い式、もしくは述語のみからなる単純文、もしくは括弧で囲まれている値を返す文である。・リスト式は、リスト引用符(「」)で囲まれたリストである。・リスト式の値は、そのリストそのものである。・述語には名詞形と動詞形がある。・後置詞の直前には、動詞形の述語は直接置けない。・動詞形は必要に応じて活用する。・例外を発生させる述語、およびそれをとらえる述語がある。将来的にはクラスが扱えるようにしてもいいが、とりあえずそれを考えない。作るとすればこんな感じになるだろう。クラス(分類):・インスタンス変数は、「(インスタンス名)の(変数)」で表記する。・クラス変数は、「(クラス名)の(変数)」で表記する。・インスタンスメソッドは、「(インスタンス名)を(メソッド)」で表記する。・クラスメソッドは、「(クラス名)を(メソッド)」で表記する。これらの規則に従って基本命令が定義されている。