2011-11-04 12 views
5

Iがソケットから見えるバイト配列内の文字列を受け取る。文字列変換のバイト配列の文字列の終わりを検出するにはどうすればいいですか?

[128,5,6,3,45,0,0,0,0,0] 

ネットワークプロトコルによって指定されたサイズは、(ゼロを含む)の文字列の合計な長さであるので、私のexemple 10.

私は単純に行う場合:

String myString = new String(myBuffer); 

私は、文字列5不正解caracterの最後に持っています。変換は文字列caracter(0)の終わりを検出していないようです。正しいサイズと私はこれを行う正しい文字列を取得するには

int sizeLabelTmp = 0; 
//Iterate over the 10 bit to get the real size of the string 
for(int j = 0; j<(sizeLabel); j++) { 
    byte charac = datasRec[j]; 
    if(charac == 0) 
     break; 
    sizeLabelTmp ++; 
} 
// Create a temp byte array to make a correct conversion 
byte[] label = new byte[sizeLabelTmp]; 
for(int j = 0; j<(sizeLabelTmp); j++) { 
    label[j] = datasRec[j]; 
} 
String myString = new String(label); 

は、問題を処理するためのより良い方法はありますか?

おかげ

答えて

7

0 "は、文字列の文字の終わり" ではありません。それはただのバイトです。それが文字列の最後に来るかどうかは、使用しているエンコーディング(およびテキストの内容)によって異なります。たとえば、UTF-16を使用した場合、他のすべてのバイトはASCII文字の場合は0になります。

あなたが最初の0は文字列の終わりを示し確認している場合は、あなたが与えてくれたコードのように何かを使用することができますが、私はとしてそれを書き換えたい:

int size = 0; 
while (size < data.length) 
{ 
    if (data[size] == 0) 
    { 
     break; 
    } 
    size++; 
} 

// Specify the appropriate encoding as the last argument 
String myString = new String(data, 0, size, "UTF-8"); 

I 強くは、プラットフォームのデフォルトエンコーディングを使用するだけでなく、移植性がなく、すべてのUnicode文字を使用できないことを推奨しています。しかし、あなたは決して恣意的に決定することはできません。このデータを生成し消費するすべてがエンコードに同意する必要があります。

プロトコルを制御している場合は、文字列の前に長さ接頭辞を挿入して、エンコードされたフォームに含まれるバイト数を示すことができる場合は、より良いでしょう。そうすれば、正確な量のデータを正確に読み取ることができ、何らかの理由でデータが切り捨てられているかどうかを知ることができます。

+0

+1エンコードを考慮してください。ソケット経由で受け取ったものがシリアル化されたJava Stringであれば大丈夫です。 –

+0

@G_H:「ちょうどシリアライズされたJava String」は、シリアライズ形式が何であるかを実際に指定していません。 OPがJavaバイナリのシリアル化を使用していた場合は、とにかくこの操作を明示的にやっていないでしょう...もしそれが他のシリアル化形式であれば、*を*知る必要があります。 –

+0

私はおそらく話を止めるべきです...事実、私はいつも直列化から離れていて、その細部をよく知っていません。 JAXBまたはJPAは通常、私がオプションと考える唯一のものです。 –

2

Javaの文字列は、他の言語と同様に0で終了しません。 0は文字列に現れることが許されているいわゆるヌル文字になります。私はあなたが0の配列の最初のインデックスを検出し、サブアレイを使用してStringを構築する(残りのすべてが0になると仮定して)、または単にStringを構築してtrim()を呼び出すトリミングスキームを使用することをお勧めします。これは、ASCIIコード32以下の文字である先頭と末尾の空白を削除します。

保存しなければならない空白がある場合は、後者は機能しません。 StringBuilderを使用し、それらがヌル文字である限り、末尾の文字を削除すると、その場合にはうまくいくでしょう。

2

いつでもバイト配列の最後から開始し、最初のゼロ以外の値になるまで後方に移動できます。それから新しいバイトにそれをコピーし、次にそれをストリングしてください。これが欲しいと思っています:

byte[] foo = {28,6,3,45,0,0,0,0}; 
    int i = foo.length - 1; 

    while (foo[i] == 0) 
    { 
     i--; 
    } 

    byte[] bar = Arrays.copyOf(foo, i+1); 

    String myString = new String(bar, "UTF-8"); 
    System.out.println(myString.length()); 

あなたの結果は4になります。

1

read()メソッドによって返された読み取り回数を無視しているように見えます。末尾のnullバイトはおそらく送信されませんでしたが、おそらくバッファの初期状態から残っています。

int count = in.read(buffer); 
if (count < 0) 
    ; // EOS: close the socket etc 
else 
    String s = new String(buffer, 0, count); 
+0

私のOPに示されているバッファは、パケット全体の単なる抽出です。文字列は、他のデータの真ん中に送信されます。 – grunk

+0

@grunkプロトコルは、その文字列がヌル終端か長さ接頭辞のどれかであることを伝える必要があります。 – EJP

9

5月が遅すぎるかもしれませんが、他人を助けるかもしれません。最も簡単なことはnew String(myBuffer).trim()で、あなたが望むものを正確に与えることができます。

1

オリジナルのOPが述べたプロトコルの考慮事項には触れないでください。後続のゼロをトリミングするにはどうしたらいいですか?

public static String bytesToString(byte[] data) { 
    String dataOut = ""; 
    for (int i = 0; i < data.length; i++) { 
     if (data[i] != 0x00) 
      dataOut += (char)data[i]; 
    } 
    return dataOut; 
} 
関連する問題