2009-09-06 14 views
5

、のは、私は3バイトJavaは:例えば

byte a[] = {1,2,3,0,1,2,3,0,0,0,0,4}; 
byte r[] = magic(a); 
System.out.println(r); 

結果

{1,2,3,0,1,2,3,4} 

Iよりも長い0のすべての連続セグメントの配列から削除したいとしましょうバイト配列からゼロのcontiniousセグメントを削除しますJavaでは正規表現のようにしたいが、Stringではなくバイト配列で処理する。

私は組み込みを助けることができる(または良いサードパーティツールがありますか)、またはゼロから作業する必要がありますか?

文字列はUTF-16なので、前後の変換は良い考えではありませんか?少なくとも、それは無駄なオーバーヘッド...多くの?

+0

ご利用の場合のパフォーマンスとメモリ使用量がどのように重要なのですか?一般に、RAMは安価であり、CPUは高速です。あなたは実際にボトルネックを見つけましたか、効率を心配するケースですか? 8ビットエンコーディングを使用してbyte []をStringに変換して、簡単に試してみてください。正規表現を行い、パフォーマンスをチェックしてください。結局のところ、ANSI環境で16ビットの文字列を使用する非効率なJava文字列が通常の使用にどのように影響するか心配する必要はありません。 –

+1

高性能アプリケーションでは、ラムの使用よりもサイクルが心配です。 – Mike

+1

ベンチマークの価値はまだあります。 Hotspot VMはホットスポットのコードをマシンコードに変換します。マシンコードは、32ビットのマシンワードに収まるため、8ビットデータと同じ速度で16ビットデータを処理します。たとえそれが遅すぎるとしても、それを見つけるのに多くの時間を費やすことはありません。 –

答えて

1

正規表現は、仕事のためのツールではありません、あなたの代わりに漂って合理的なByteStringライブラリがありますが、私が見た誰もが彼らの上に、一般的な正規表現ライブラリを実装していない最初から

-1

Java RegexはCharSequencesで動作します。既存のバイト配列をラップするには、CharBufferを使用します(char []にキャストする必要があります)。それをそのまま解釈して正規表現を実行しますか?

+0

文法が間違っていたり、コードがなく、Unicodeの置換の疑問符または疑問の質問のいずれかです。そのような[X/Y質問](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)を尋ねる人々にとっては理解しづらい。改善するまで下降。 –

1

どのように正規表現があなたの望むことに役立つか分かりません。あなたは、Run Length Encodingを使ってそのバイト配列をエンコードし、 "30"(3つの0を読み込む)を空の文字列に置き換え、最後の文字列をデコードします。 WikipediaにはJavaの単純な実装があります。

+1

私は3 0はほんの一例だと思った。 –

1

ことを実装する必要があります。

私はあなたの問題を解決するに直接ではなく、正規表現ライブラリを実装:)

あなたは、文字列とバックに変換を行う場合、あなたはおそらく、あなたの0バイトのラウンドトリップを与え、既存のエンコーディングを見つけることができませんお勧めします。その場合、独自のバイト配列< - >文字列変換器を記述する必要があります。トラブルの価値がない。

24
byte[] a = {1,2,3,0,1,2,3,0,0,0,0,4}; 
String s0 = new String(a, "ISO-8859-1"); 
String s1 = s0.replaceAll("\\x00{4,}", ""); 
byte[] r = s1.getBytes("ISO-8859-1"); 

System.out.println(Arrays.toString(r)); // [1, 2, 3, 0, 1, 2, 3, 4] 

範囲内のすべてのバイト0x00..0xFF有効な文字にマップ、および

  • それぞれ他のエンコーディングとは異なり、

    • 、ので、私はISO-8859-1(latin1の)を使用それらの文字のlatin1エンコーディングと同じ数値があります。文字列は、元のバイト配列と同じ長さである、あなたは\xFF構造とその数値によって任意のバイトを一致させることができます、そしてあなたが情報を失うことなくバックバイト配列に結果の文字列を変換することができることを意味し

    文字列形式のデータを表示しようとしません。すべての文字は有効ですが、多くは印刷可能ではありません。また、文字列形式でデータを操作しないでください。誤っていくつかのエスケープシーケンス置換や別のエンコーディング変換を実現せずに行うことがあります。実際には、私はは全くこのようなことをしているをお勧めしませんが、それはあなたが尋ねたものではありません。:)

    また、この技術は他のプログラミング言語や正規表現のフレーバーでは必ずしも機能しないことに注意してください。それぞれを個別にテストする必要があります。

  • +3

    それは本当に賢いです。 –

    +1

    ハッキー。私はそれが大好きです:) –

    0

    バイト配列をStringに変換し、正規表現を実行してから変換することをお勧めします。ここに実例があります:

    public void testRegex() throws Exception { 
        byte a[] = { 1, 2, 3, 0, 1, 2, 3, 0, 0, 0, 0, 4 }; 
        String s = btoa(a); 
        String t = s.replaceAll("\u0000{4,}", ""); 
        byte b[] = atob(t); 
        System.out.println(Arrays.toString(b)); 
    } 
    
    private byte[] atob(String t) { 
        char[] array = t.toCharArray(); 
        byte[] b = new byte[array.length]; 
        for (int i = 0; i < array.length; i++) { 
         b[i] = (byte) Character.toCodePoint('\u0000', array[i]); 
        } 
        return b; 
    } 
    
    private String btoa(byte[] a) { 
        StringBuilder sb = new StringBuilder(); 
        for (byte b : a) { 
         sb.append(Character.toChars(b)); 
        } 
        return sb.toString(); 
    } 
    

    もっと複雑な変換については、私はレクサーを使用することをお勧めします。 JavaCCとANTLRの両方はバイナリファイルの解析/変換をサポートしています。

    8

    私はreg-exが仕事のための正しいツールであるかどうかは疑問ですが、あなたが使用したい場合は、バイト配列にCharSequenceラッパーを実装することをお勧めします。これのようなもの(私はちょうどこれをコンパイルされたものではなく、直接書きました...しかしあなたはそのアイデアを得ます)。

    public class ByteChars 
    implements CharSequence 
    
    ... 
    
    ByteChars(byte[] arr) { 
        this(arr,0,arr.length); 
        } 
    
    ByteChars(byte[] arr, int str, int end) { 
        //check str and end are within range here 
        strOfs=str; 
        endOfs=end; 
        bytes=arr; 
        } 
    
    public char charAt(int idx) { 
        //check idx is within range here 
        return (char)(bytes[strOfs+idx]&0xFF); 
        } 
    
    public int length() { 
        return (endOfs-strOfs); 
        } 
    
    public CharSequence subSequence(int str, int end) { 
        //check str and end are within range here 
        return new ByteChars(arr,(strOfs+str,strOfs+end); 
        } 
    
    public String toString() { 
        return new String(bytes,strOfs,(endOfs-strOfs),"ISO8859_1"); 
        } 
    
    +0

    私はこのアプローチを実装し、それは治療を働いた!明らかに、あなたは任意の文字セットのデコードを実行していないので注意する必要がありますが、doctypeの検出のようなものは完璧です。 – sigpwned

    0

    他の回答によって提案正規表現を利用した実装では、コピーが出力アレイへの入力アレイからのバイトそのループを使用して単純な実装よりも最大8倍遅いです。

    実装では、入力配列が1バイトずつコピーされます。ゼロシーケンスが検出された場合、出力配列インデックスは縮小されます(巻き戻されます)。入力配列を処理した後、中間配列が入力配列の長さで初期化されるので、出力配列はもう一度コピーされてその長さを実際のバイト数に調整します。 (3以下)第0バイトに巻き戻し及びこれらの要素をコピーすることによって、不要なコピーを防止する

    /** 
    * Remove four or more zero byte sequences from the input array. 
    * 
    * @param inBytes the input array 
    * @return a new array with four or more zero bytes removed form the input array 
    */ 
    private static byte[] removeDuplicates(byte[] inBytes) { 
        int size = inBytes.length; 
        // Use an array with the same size in the first place 
        byte[] newBytes = new byte[size]; 
        byte value; 
        int newIdx = 0; 
        int zeroCounter = 0; 
    
        for (int i = 0; i < size; i++) { 
         value = inBytes[i]; 
    
         if (value == 0) { 
          zeroCounter++; 
         } else { 
          if (zeroCounter >= 4) { 
           // Rewind output buffer index 
           newIdx -= zeroCounter; 
          } 
    
          zeroCounter = 0; 
         } 
    
         newBytes[newIdx] = value; 
         newIdx++; 
        } 
    
        if (zeroCounter >= 4) { 
         // Rewind output buffer index for four zero bytes at the end too 
         newIdx -= zeroCounter; 
        } 
    
        // Copy data into an array that has the correct length 
        byte[] finalOut = new byte[newIdx]; 
        System.arraycopy(newBytes, 0, finalOut, 0, newIdx); 
    
        return finalOut; 
    } 
    

    第2のアプローチは、興味深いことに、最初のアプローチよりも少し遅かったです。

    すべての3つの実装は、いくつかの量と長さのゼロシーケンスを持つ8 x 32KBの入力配列で1,000回の反復でPentium N3700プロセッサでテストされました。正規表現の手法と比較して最悪のパフォーマンス向上は、より速く、であった。

    完全なテストリグは、ここで見つけることができます:https://pastebin.com/83q9EzDc