2011-01-10 14 views
7

私は複雑な正規表現を持っています。私はそれを巨大なファイル全体の内容と一致させたいと思います。主な関心事は、ファイルが実際に非常に大きく、メモリが不足していることが明確な可能性があるため、効率です。私はファイル全体に効率的に正規表現を適用したい

私は何とか正規表現マッチャーを通してポンピングしながらコンテンツを "バッファ"する方法はありますか?

答えて

6

はい、Pattern.match()CharSequenceになります。

ByteBuffer bb = ...; // acquire memory mapped byte buffer 
CharBuffer cb = bb.asCharBuffer(); // get a char[] 'view' of the bytes 

...とCharBufferCharSequenceを実装しているので、あなたがしている:あなたの入力は任意の「プロローグ」なしで文字を表現するために、正確に2バイトを使用して文字セットにすでにある場合

、あなただけの必要完了しました。

一方

、あなたには、いくつかの他の文字セットにバイトをデコードする必要がある場合、あなたはあなたの仕事はCharBuffer以来、切り出されていますが、文字セットに依存しないで、そしてCharsetDecorder.decode(ByteBuffer)は内部として新しいCharBufferほぼ同じサイズを割り当てます。入力バイト。

あなたが小さなバッファで離れることができるかどうかは、あなたの正規表現の公正なビットと、マッチ結果で何をするかによって決まります。しかし、基本的なアプローチはCharSequenceを実装し、メモリマップByteBufferをラップし、小さい「」と「CharsetDecoder」をラップします。あなたはバイトをオンデマンドでデコードするためにCharset.decode(ByteBuffer,CharBuffer,boolean)を使い、正規表現マッチャーの一般的な方向が 'forward'であり、関心のある入力がかなり小さい塊になることを願っています。ラフなスタートとして

class MyCharSequence implements CharSequence { 

    public MyCharSequence(File file, Charset cs, int bufferSize) throws IOException { 

     FileInputStream input = new FileInputStream(file); 
     FileChannel channel = input.getChannel(); 
     this.fileLength = (int) channel.size(); 
     this.bytes = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength); 
     this.charBuffer = CharBuffer.allocate(bufferSize); 
     this.decoder = cs.newDecoder(); 

    } 

    public int length() { 
     // ouch! have to decode the lot, even if you don't choose to keep it all handy 
    } 

    public char charAt(final int index) { 
     while (/* not yet decoded target char[] */) { 
      this.decoder.decode(this.bytes, this.charBuffer, true); 
     } 
     // don't assume 2-bytes == a char unless that's true for your charset! 
    } 

    public CharSequence subSequence(final int start, final int end) { 
     // this'll be fun, too 
    } 

    private long fileLength; 
    private MappedByteBuffer bytes; 
    private CharBuffer charBuffer; 
    private CharsetDecoder decoder; 

} 

あなた自身のはるかに単純なCharSequenceラッパーでCharBufferを完全にデコードラップ、及び方法は、実際に自分の与えられた入力のために呼ばれているかログインすることは有益であるかもしれません、あなたの開発ボックスに大きなヒープを付けて実行したとき。このアプローチがあなたの特定のシナリオでうまくいくかどうかは、それがあなたに考えを与えます。

+0

私はちょうど同様の答えを書いて、あなたがすでにそれを投稿しているのを見ました! – AlexR

+2

すごくすごく:-)また、[http://java.sun.com/developer/technicalArticles/releases/nio/]は便利です。特に、「マップされたファイル」のセクション。 –

+0

私はファイルのMappedByteBufferを取得し、Charset.defaultCharset()。newDecoder()。decode(buffer)のようなことをすることができますが、これはバッファのコピーを作成しませんか? – Jake

0

Javaはわかりませんが、/^.+$/のようにファイルの内容全体を一致させることはできますか?
ファイルはあなたの正規表現に基づいてチャンクに分割されますが、あなたはどこがわからないのですか?
正規表現のエンジンは面白いです。メモリマップされたファイルを作成できるのであれば、それは良いスタートになります。

あなたの正規表現を見てみましょう。通常、正規表現を調べて2つのアンカーポイントを決定し、オーバーフロー(オーバーラップ)が引き継がれ、ウィンドウがファイルのさらに下に移動するフローティングバッファのカットオフとして使用できます。

私はこれをPerlモジュールで何度もやっています。そして、ファイルの始めと終わりのアンカー以外のものでは、簡単に行うことができます。

関連する問題