北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

ファイルから正規表現でデータを抜く

perlで書くとこうです。

use strict;

open(IN, 'huge.txt');
while(<IN>){
	while(/key?s*=?s*'([?w?-]+)'/g){
		print $1, "?n";
	}
}
close(IN);

で、java使って書いてみたわけです。

import java.io.*;
import java.util.regex.*;

class Test{
	static final private File file = new File("huge.txt");
	static final private Pattern pattern = 
                             Pattern.compile("key??s*=??s*'([??w??-]+)'");

	public static void main(String[] args){
	    try{
		BufferedReader br = null;
		br = new BufferedReader(
			      new InputStreamReader(
             	                   new FileInputStream(file), 
				   "JISAutoDetect"
			      )
		);

		String str = null;
		while( (str = br.readLine()) != null ){
		    Matcher m = pattern.matcher(str);
		    while(m.find()){
			System.out.println(m.group(1));
		    }
		}
		
		br.close();
	    }catch(FileNotFoundException e){
		e.printStackTrace();
		return;
	    }catch(UnsupportedEncodingException e){
		e.printStackTrace();
		return;
	    }catch(IOException e){
		e.printStackTrace();
		return;
	    }

	}

}

なんじゃこりゃーー!!! 特に、イタダケナイ部分が二カ所あります。

まず、BufferedReaderによるラッピングの部分。ファイル開くだけで6行も浪費されてます。perlのopenと同等のファサードメソッドでも作るべきですかね。

後は、UnsupportedEncodeingException。この例外は事前のチェックで防げる性質だと思うので、チェックされる例外になっているのは非常にうざったいです。FileNotFoundExceptionとIOExceptionは、まあ、このメソッドの実行時にしかわからないので仕方ない気もしますが。

で、長ったらしくて書くのに時間かかる上にコンパイルまで必要で面倒きわまりないjava ver.ですが、極めつけは速度まで遅いです。環境によりますが、うちの環境ではperlの1.5倍の時間がかかります。*1

じゃあ、なんで遅いかなあと考えてみたんですが、javaは内部ではUTF-16で文字列を保持する*2ってことが関係してるんじゃないでしょうか。つまり、生のバイト列に対して変換処理が走ります。perlは先に挙げたコードでは生のバイト列をそのまま扱い、変換は行いません。試しに、open時に'<:encoding(sjis)'*3なんてのを渡してやると、perlもがくっと遅くなります。

他には、javaが文字列処理を苦手とすることもあります。これはStringクラスがイミュータブルなためで、文字列を変更するためには基本的にコピーが必要です。少量の文字列を扱う場合ならいいですが、大量の文字列を扱う場合には影響も大きくなってきます。今回の実装部分ではあまり無駄な部分は見当たらないですが、もしかするとreadLine()やらmatcher()やらgroup()やらの実装で、文字列をコピーしている箇所があるのかもしれません。

で、結論。まず、パフォーマンスに関しては色々予想はしたものの、はっきり言って環境によって違うし、もっと規模が大きくなってメソッド呼び出しが発生してくると、動的バインディングperlはあっという間に不利になるってこともあるので、とりあえず言語間のパフォーマンス差異は気にしないってのがいいんじゃないかと思います。まあでも、それ以上に、ソースを見て一目瞭然ですが、ファイルや文字列の整形処理はPractical Extraction and Report Languageの名を持つperlを使うべきです(笑)。*4

そう、適材適所。


2006.07.03追記。UnsupportedEncodeingExceptionは実行環境による例外なのでチェックされる例外なんですね。WORAなんて、すっかり忘れてました(´-`)。

*1:実は1.5倍と言うのはprintln()を略した時の値ですが、println()があまりに遅かったので。で、この件は未調査。

*2:確かUTF-8じゃなかったはず??

*3:PerlIOによりutfフラグを立てさせるための引数

*4:そうなると皮肉なことに、serverサイドで生き残っているjavaは、実はWEBやxmlのI/O・加工処理(=テキスト処理)にはあんまり適材じゃないことになるorz