月別アーカイブ: 2008年5月

Java: 文字列の先頭・末尾の文字を削除するstrip()メソッド

テキストマイニングを行う際、文書を単語集合に区切ったのはいいけれど、単語の先頭・末尾に以下のような文字が入っている場合は辞書に格納する際に削除したいですね。

単語の前後に複数の記号((ピリオドやクォーテーション、カンマやコロンなど))が入り混じった文字列から、それらを刈り取る方法を採り上げます。0からゴリゴリ文字の条件判定文を書いたり、正規表現でマッチしたときに刈り取りしたりするのも良いですが、オープンソースで今回のケースにマッチしたクラスメソッドがありますので、その使い方と仕組みを簡単に紹介します。

StringUtils#strip(String str, String stripChars)

ソース・バイナリ共にApache CommonsLang Downloadsのページからダウンロードできます。

StringUtils#strip(String str, String stripChars)メソッド引数は、
+第一引数:刈り取り対象文字列(テキスト)
+第二引数:刈り取る文字
例えば、

の時のresultの中の文字列はHiとなります。

stripメソッドは内部でstripStartとstripEndメソッドを実行しています。前者は文字列の先頭部分の刈り取りを、後者は末尾部分の刈り取りを行っています。
以下に、stripEndのソースを引用します。

ここで重要な処理部分はソース最後の、

の部分です。
刈り取り対象文字列の末尾から順に文字を調べていきますが、その文字を指すパラメータにendを、その初期値はテキストの文字列長でループごとにデクリメントされていきます。そのendが指す文字がstripCharsに含まれているか否かを判定しているところが、

stripChars.indexOf(str.charAt(end - 1)) != -1

ですね。最終的にsubstringメソッドで部分文字列を取得することで刈り取っています。

これ書いた人上手いなー。indexOfやcharAtの使い道の幅が広がった感じがします。

検索エンジンを実装 (5)OR演算

前回がAND演算でしたので今回はOR演算ついて紹介します。今記事で紹介している演算アルゴリズムよりも高効率なものは存在するようですが、今回は割愛します。

OR演算処理の概要

OR演算結果

上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、リスト要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、OR演算は主に以下の処理内容を繰り返します。

  1. if a < b then 要素aをCの末尾に追加し、aにリストAの次の要素を代入
  2. if a = b then 要素aをCの末尾に追加し、A, Bが指す次の要素をa, bに代入
  3. if a > b then 要素bをCの末尾に追加し、bにリストBの次の要素を代入

ソースコード

今回はOR演算処理を行う部分(メソッド)のみを示します。後で示す実行結果は、前回ブログラムをベースにintersect(postsSet)の箇所を今回のものに置き換えたものです。

OR演算の実行結果

おー、なんだかもりあがってきましたねー。

話は変わりますが、最近よく実感していることの一つに、ソフトウェアの仕様が変更されると場合によっては設計を根本から変える必要があること。

そして、手がけているソフトウェアが今後アップグレードを繰り返していくと予測できるなら、現時点で取り組んでいる設計に費やす時間はほどほどに、ということです。OO分析設計を用いて保守性・拡張性を高めるのもいいけれど、その設計上での拡張が今後の仕様変更に耐えうるとは限りません。

勿論、最初の設計が肝心であることには変わりないですけれど。それでも留意。

Yahoo!検索 サイトエクスプローラー を利用するブックマークレット

追記:Yahoo!検索 サイトエクスプローラーのサービスって終了してしまったんですね。。

任意のWebページ上でワンクリックでサイトエクスプローラー – Yahoo!検索のインデックス検索が出来るブックマークレットを作ってみました。

別ウィンドウで開く

下のリンクをお気に入りにドラック&ドロップして下さい。

サイトエクスプローラー(別)

IEの場合、その際のホップアップは許可してください。ホップアップ確認がわずらわしい場合は下の「同じウィンドウで開く」バージョンを利用してください。

同じウィンドウで開く

サイトエクスプローラー(同)

コード

使い方

任意のサイトで上述で作成したお気に入りをクリックすると、そのサイトのインデックス検索が行われます。

検索エンジンを実装 (4)AND演算

AND演算処理の概要

AND演算結果

上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、AND演算は主に以下の処理内容を繰り返します。

  1. if a < b then aの次の要素をaに代入
  2. if a = b then 要素aをCの末尾に追加しA, Bが指す要素を一つ進める

プログラムの主な処理内容

  1. 検索対象テキストを単語に分割。
  2. 単語を転置インデックスに登録。ここで、1単語あたりに格納する情報は、その単語の出現頻度とその文書ID。転置インデックスのデータ構造はTreeMapを使用しkeyに単語、valueはIndexRecordでputします。
  3. ユーザからの標準入力をパースしAND演算(Intersectメソッドで実現しています)。

以下に、ソースコードと実行結果を示します。

IndexRecord.java

1つのトークン(単語)に対するインデックス情報(docIDリストや出現頻度情報)

BooleanTest.java (AND演算のテストプログラム)

FreqComparator.java (ArrayList要素のソート用)

実行結果

おー、なんだか楽しくなってきましたね。

文字列の区切り方

今回は検索対象テキストを英文に絞ったため、テキスト中の空白文字で区切ることでトークンを抽出できました。対して、日本語テキストの場合は区切り記号等は無い為、n-gramか形態素辞書などを用いてトークンに区切ることで実現できます。日本語文の区切り方は色々ありますが、中でも簡単な方法は、文字種(英文字、記号、ひらがな、カタカナ、漢字)の違いを区切りの境界と捉える方法です。

余談ですが、ブラウザやエディタ等で文字の上でダブルクリックするとカーソル下の文字列が選択状態になりますが、その範囲を決定する際に上述の方法が応用されているようです。ソフトによってはトリプルクリックするとカーソル下の行全体が選択状態になります(使うと編集が楽です)。

JavaプログラムからExcite翻訳を利用

POSTメソッドを用いてWebページのフォームにリクエストを送信し、そのレスポンスを取得するプログラム例として、エキサイト 翻訳を利用してみます。
送信クエリの1つは翻訳言語設定、2つ目は翻訳対象文字列でレスポンスのWebページから翻訳された文字列を抽出します。

ソースコード

実行結果

Java MSN Messenger Library (JML)で翻訳ロボを作る

Java MSN Messenger Library (JML)とは Windows Live Messenger 上の通信プロトコルMSNP8-MSNP12をサポートするライブラリです。主に、メンバーの会話に自動応答するチャットボット(Chat Bot)や人工無脳などを作る際に用いられます。

今回は、ライブラリに付属しているサンプルプログラムのEchoMessengerクラスにこの翻訳クラスをかませて、メンバーの発言を翻訳し、その文字列色をランダムで選択した色で応答するチャットボットを作成してみました。

実行結果は下図になります。
JML翻訳ロボの実行結果例

コンストラクタでの翻訳言語設定が逆でも、文字列が英語or日本語に統一されていれば、Excite翻訳側がそれに合わせて適当な言語で翻訳するみたいです。
最後に、

礼儀正しくクローリングする際は

  • robots.txtやメタタグを守るように
  • 相手サーバに負荷をかけすぎないように
  • 相手Webサイトポリシー(利用規約)を守るように
  • 頻繁に使いたいモノなら、同機能のWebサービスを使うこと(利用規約内で)

うーん、今回のようなプログラムの利用はあまりよくないようでね。

java.lang.OutOfMemoryErrorが発生する原因とその解決法の一例

JVMがGCを行えるように、開放するインスタンスへの参照を切っていたのだけれど、なぜか例外が投げられ続けていました。色々調べてみたら、java.io.ObjectOutputStream#writeObject(Object obj)の部分で、書き出されたobjの状態が保持され続けるので、いつまでたってもGCが始まらなかったのが原因でした。

解決法は、java.io.ObjectOutputStream#reset()メソッドでストリームが保持している状態を無効にすることで、不要インスタンスをGCの対象に入れることでした。