[[python/集合知3章]] 2009/02/08からのアクセス回数 &counter; ** はじめに [#hca3206d] pythonを使っていて感じるのは、便利だけどパッケージがマシンに依存し過ぎている ように思われます。 例えば、スクリプトを別のマシンで動かそうとしたときに、パッケージのインストールから はじめなくてはならないときに痛烈に感じます。 そこで、ここではjythonとjavaを使ってpythonのマシン依存部分をjavaのクラスとjythonの スクリプトでラップしてみようと思います。 ** 日本語の分かち書き [#bcf63440] [[python/集合知3章]]と同様に、ブログに対する日本語処理からはじめます。 *** senのインストール [#l6877481] chasenと同様の機能を持つjavaのライブラリにSenがあります。 残念ながら、maven2のパッケージとして提供されていないので、[[java.netのsenのドキュメント&ファイルページ>https://sen.dev.java.net/servlets/ProjectDocumentList?folderID=755&expandFolder=755&folderID=0]]からsen-1.2.2.1.zipをダウンロードしてください。 - ZIPファイルの解凍 ここでは、 -- ダウンロードしたファイルは、~/Downloadedディレクトリ -- 解凍先は、~/localディレクトリ にあるものとして説明します。 -- unzipで解凍します #pre{{ $ cd ~/local/ $ unzip ~/Downloaded/sen-1.2.2.1.zip $ cd sen-1.2.2.1/ }} - 辞書の作成 つぎにantを使って辞書を作成します。 -- 辞書の作成にはperlが必要です。ここでは/usr/bin/perlを使います。 #pre{{ $ cd dic $ ant -Dperl.bin=/usr/bin/perl }} - jarファイルのmaven2への登録 最後にsen.jarファイルをmaven2で利用できるようにローカルディポジトリに登録します。 #pre{{ $ cd ../lib $ mvn install:install-file -Dfile=./sen.jar -DgroupId=sen \ -DartifactId=sen -Dversion=1.0 -Dpackaging=jar }} *** pythonlibの作成 [#t0a1c539] 作成したライブラリは1つのjarにまとめておくとjythonから利用するときに便利です。 ここでは、pythonlibというEclipseのプロジェクトをmaven2を使って作成します。 - プロジェクトの作成 最初にjythonlibのプロジェクトを作成します。 #pre{{ $ mvn archetype:create -DgroupId=jythonlib -DartifactId= jythonlib -Dversion=0.1 }} - pom.xmlの編集 pom.xmlを編集して、sen.jar, common-logging.jarを使えるようにします。 以下の定義をdependenciesに追加 #pre{{ <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>sen</groupId> <artifactId>sen</artifactId> <version>1.0</version> </dependency> }} 次にbuildを追加し、javaのバージョン、UTF-8の設定、jarファイルの設定、依存ライブラリのコピーをセットします。 #pre{{ <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>jythonlib.Sen</mainClass> <packageName>jythonlib</packageName> <addClasspath>true</addClasspath> <addExtensions>true</addExtensions> <classpathPrefix>./lib</classpathPrefix> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> }} この設定は、結構役に立ちますから、覚えておいた方がいいですよ。 - Eclipseプロジェクトに対応 以下のコマンドで、Eclipseの.projectと.classpthを作成します。 #pre{{ $ mvn eclipse:eclipse -DdownloadSources=true }} *** Senクラスの作成 [#z42e3be5] senの形態素解析を実行し、jythonにその結果を返すクラスSen.javaを作成します。 変換部分は、 #pre{{ private String[] parts = {"形容詞", "形容動詞", "副詞", "連体詞", "名詞", "動詞"}; public List<String> sparse(String text) { List<String> list = new ArrayList<String>(); try { StringTagger tagger = StringTagger.getInstance(); Token[] token = tagger.analyze(text); String term = null; for (int i = 0; i < token.length; i++) { // 未知語、英語の単語 if ((term = token[i].getTermInfo()) == null) { list.add(token[i].getSurface()); } else { for (String part : parts) { if (term.startsWith(part)) { list.add(token[i].getBasicString()); break; } } } } } catch (Exception e) { } return (list); } }} と簡単です。 *** Jythonとjava間の日本語処理 [#x6518ada] jythonとjavaとの日本語は、結構大変です。ここでは以下の方針で文字を渡すことに します。 - jythonからjavaへは、UTF-8でエンコーディングされたバイト文字列を渡す javaでの変換は以下のようになります。 #pre{{ jTxt = String(txt, "utf-8") }} - javaからjythonへは、unicodeにエンコーディングされた文字列を渡す javaでの変換は以下のようになります。 #pre{{ uTxt = String(word.getBytes('utf-8'), 'iso-8859-1') }} sen用のsplitメソッドをsplit.pyに以下のように定義します。 #pre{{ # -*- coding: utf-8 -*- import japanese import codecs import jarray import jythonlib.Sen import java.lang.String from java.lang import * parts = ["形容詞", "形容動詞", "副詞", "連体詞", "名詞", "動詞"] parts = jarray.array([String(part, "utf-8") for part in parts], java.lang.String) def split(txt): jTxt = String(txt, "utf-8") sen = jythonlib.Sen(parts) words = sen.sparse(jTxt) outList = [] for i in range(len(words)): word = String(words.get(i)) outList.append(String(word.getBytes('utf-8'), 'iso-8859-1')) return outList }} *** 動作確認 [#p94f14f0] senを使った分かち書きのテストをします。 #pre{{ # -*- coding: utf-8 -*- import japanese import split txt = "オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。" print txt words = split.split(txt) for word in words: print word }} を実行すると、 #pre{{ オリジナルのソースは、原書著者TobesのページからPCI_Code.zipと してダウンロードできます。 オリジナル ソース 原書 著者 Tobes ページ PCI _ Code . zip する ダウンロード できる }} と出力されます。 chasenと比べると英語の文字も正しく処理されること、「から」が名詞ではなく正しく助詞? として認識されています。 ** コメント [#tbf261fc] この記事は、 #vote(おもしろかった,そうでもない,わかりずらい) 皆様のご意見、ご希望をお待ちしております。 #comment_kcaptcha