2016-10-02 13 views
2

私は現在、16進エディタインターフェイスを使用してByteBufferを編集し、対応するテキストをJTextPaneで編集できるアプリケーションを開発中です。現在の問題は、JTextPaneにStringが必要なためです。値を表示する前に、ByteBufferをStringに変換する必要があります。ただし、変換中に無効な文字は、文字セットのデフォルトの置換文字に置き換えられます。これは無効な値をスクラッシュします。そのため、バイトバッファに変換すると、無効な文字の値がデフォルトの置換文字のバイト値に置き換えられます。文字列に無効な文字のバイト値を保持する簡単な方法はありますか?私は次のstackoverflowの記事を読んだことがありますが、通常、人は印刷できない文字を置き換えたいので、それらを保存する必要があります。JavaでのByteBufferとStringの間の変換の問題

Java ByteBuffer to String

Java: Converting String to and from ByteBuffer and associated problems

これを行う簡単な方法はありますか私は、テキストエディタで起こるとのByteBufferに適用するすべての変更を追跡する必要がありますか?

ここに問題を示すコードがあります。コードはByteBufferの代わりにbyte []を使用しますが、問題は同じです。

 byte[] temp = new byte[16]; 
     // 0x99 isn't a valid UTF-8 Character 
     Arrays.fill(temp,(byte)0x99); 

     System.out.println(Arrays.toString(temp)); 
     // Prints [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103] 
     // -103 == 0x99 

     System.out.println(new String(temp)); 
     // Prints ���������������� 
     // � is the default char replacement string 

     // This takes the byte[], converts it to a string, converts it back to a byte[] 
     System.out.println(Arrays.toString(new String(temp).getBytes())); 
     // I need this to print [-103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103] 
     // However, it prints 
     //[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67] 
     // The printed byte is the byte representation of � 
+0

私はこれにコードが必要だと思います。バグのように聞こえる。また、概念的なエラーである可能性があります:正確なテキストシーケンスは、バイトに変換するのに問題がありますか? – markspace

+0

問題を示すコードを含めるように質問を更新しました。これは私のコードのバグではなく、デフォルトでこのように動作するはずです。 –

答えて

0

は特にUTF-8が間違っ

byte[] bytes = {'a', (byte) 0xfd, 'b', (byte) 0xe5, 'c'}; 
    String s = new String(bytes, StandardCharsets.UTF_8); 
    System.out.println("s: " + s); 

一つはCharsetDecoderが必要になります。そこに問題のあるバイトを無視(=削除)または置き換えるか、またはデフォルトで例外をスローすることができます。

JTextPaneの場合、HTMLを使用しているため、違反バイトの16進コードを<span>に書き込んで、赤い背景にすることができます。

ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); 
    CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); 
    CharBuffer charBuffer = CharBuffer.allocate(bytes.length * 50); 
    charBuffer.append("<html>"); 
    for (;;) { 
     try { 
      CoderResult result = decoder.decode(byteBuffer, charBuffer, false); 
      if (!result.isError()) { 
       break; 
      } 
     } catch (RuntimeException ex) { 
     } 
     int b = 0xFF & byteBuffer.get(); 
     charBuffer.append(String.format(
      "<span style='background-color:red; font-weight:bold'> %02X </span>", 
      b)); 
     decoder.reset(); 
    } 
    charBuffer.rewind(); 
    String t = charBuffer.toString(); 
    System.out.println("t: " + t); 

このコードは非常に優れたAPIを反映しているわけではありませんが、それを再生します。

+0

それは私が考えなかったことは本当に良い考えです。私が見ている唯一の問題は、Stringからbyte []に​​変換するときにJTextPaneのテキストに追加のマークアップが存在することです。それを回避する方法はありますか? –

+0

'replaceAll(" <[^> * * "、" ")'またはそれ以上のパターンマッチャーを持つループ。 –

+0

JTextPaneは、スタイル付きテキスト(StyledDocument)を使用して、テキストとは別の属性を使用することもできますが、特に編集を許可する場合は面倒です。しかし、これらのバイトをマークするために 'byteBuffer.position()'を使うことができます。 –

0

new String(temp).getBytes()はあなたのために何をしますか?

私はそれが悪いことをすることができます。

  1. それはおそらく間違っているデフォルトのエンコーディングを使用して、Stringtempを変換して、情報を失う可能性があります。
  2. デフォルトのエンコーディングを使用して、結果をバイト配列に変換し直します。 Stringbyte[]をオンにする

、あなたは常にStringコンストラクタにCharsetを渡すか、あるいは直接デコーダを使用する必要があります。あなたはバッファーから作業しているので、デコーダAPIは馴染み深いかもしれません。

Stringbyte[]にするには、正しい文字セットを使用していることがわかるように、常にgetBytes(Charset)に電話する必要があります。

コメントに基づいて、UIのバイトから16進数に変換するために、次のようなコードを記述する必要があることをここでは問題と思われています。 (その後、何かが戻って取得するために相当。)

String getHexString(byte[] bytes) { 
    StringBuilder builder = new StringBuilder(); 
    for (byte b : bytes) { 
     int nibble = b >> 4; 
     builder.append('0' + nibble); 
     nibble = b & 0xff; 
     builder.append('0' + nibble); 
    } 
    return builder.toString(); 
} 
+0

私はベストプラクティスがgetBytesとStringコンストラクタの両方がCharsetを取るべきであることを誓っていることを理解します。私がCharsetをStringコンストラクタに渡すと、この問題は依然として存在します。 'new [文字列(temp、" UTF-8 ")'は 'unsupportedEncodingException'例外をスローします。私は答えがCharsetDecoder APIを使う必要があると感じていますが、何か似たような例を使った例は見ていません。 –

+0

非UTF-8が含まれている場合は、すべての情報を保持したい場合は、文字列に変換しないでください。それぞれの 'byte'を2桁の16進数に変換する必要があります。使用しているAPIでこれを行う方法はありません。 – bmargulies

+0

@ JustinA.Mooreこれで、概念的なエラー/バグが見つかったので、マップできない文字で何をしたいのですか?*それらは定義上、マップできませんので、それらのためのいくつかの計画が必要です'Charset'のperviewの外で。 – markspace

関連する問題