2009-07-28 30 views
13

バイト配列がUTF-8でエンコードされた文字列または任意のバイナリデータである場合、どのアプローチを使用すればJavaのであるかを判断できますか?バイト配列にJavaでUnicode文字列が含まれているかどうかを確認するにはどうすればよいですか?

配列は、のようなコードによって生成されることがあります。重要な点は、我々は何を知っていないということです

byte[] messageContent = new byte[256]; 
for (int i = 0; i < messageContent.length; i++) { 
    messageContent[i] = (byte) i; 
} 

:代わりに、のようなコードによって生成された可能性が

byte[] utf8 = "Hello World".getBytes("UTF-8"); 

配列は含まれていますが、次の関数を記入するために見つけ出す必要があります:

public final String getString(final byte[] dataToProcess) { 
    // Determine whether dataToProcess contains arbitrary data or a UTF-8 encoded string 
    // If dataToProcess contains arbitrary data then we will BASE64 encode it and return. 
    // If dataToProcess contains an encoded string then we will decode it and return. 
} 

UTF-16や他のコード化メカニズムについても、これをどのように拡張するのでしょうか?

+1

同様の質問エドワード・ワイルドからのいくつかの有用なリンクを持っています - http://stackoverflow.com/questions/377294/howto-identify-utf- 8エンコードされた文字列 – JonoW

答えて

-1

デコードしてみてください。エラーがなければ、有効なUTF-8文字列です。

+2

-1:事実上のエラー。非テキストバイナリストリームを有効なUTF-8文字列としてデコードすることは可能です。 UTF-8のデコードに失敗した場合は、バイナリデータがUTF-8でないことを意味します。 UTF-8のデコードに失敗すると、バイナリデータがUTF-8であることを保証しません。 –

+1

+1絶対に正しいです。エラーなしでデコードする場合は、有効なUTF-8テキストデータです。それはラテン語、中国語、タイ語、ギリシア文字の野生ミックスのような全く意味のないテキストデータかもしれませんが、それは意味的な違いです。技術的なものではありません。 –

+1

フェアポイントマイケル。その場合、私は言っておくべきだったと思う:-1質問に答えない。それが有効なUTF-8文字列であることを宣言することは、それが文字列かバイナリデータかを調べようとしていた質問に答えることではありません。正当なUTF-8表現であるという理由だけで、元のデータがバイナリ(偶然にも有効なUTF-8となる)か、オリジナルが本物のテキストデータかどうかが分かりません。 –

10

UTF-8エンコードされた文字列は任意のバイナリデータの一種ですが、invalid in UTF-8あるバイトシーケンスを探すことができますので、すべてのケースでは、完全な精度でその決断をすることはできません。もしあなたが何かを見つけたら、それはUTF-8ではないことが分かります。

配列が大きければ、圧縮データや画像ファイルなどの "ランダムな"バイナリデータにこのようなシーケンスが現れる可能性が高いため、これはうまくいくはずです。

しかし、まったく無意味な文字列(恐らくすべての種類のスクリプトから)をデコードする有効なUTF-8データを取得することは可能です。これは短いシーケンスで起こる可能性が高くなります。あなたがそれについて心配しているならば、文字である文字がすべて同じものに属するかどうかを見るために、より詳細な分析をしなければならないかもしれません。code chartスクリプトを混在させた有効なテキスト入力がある場合、これもまた偽のネガティブをもたらす可能性があります。

0

バイト配列がByte Order Mark(BOM)で始まる場合、どのエンコーディングが使用されたのかを区別することは容易です。テキストストリームを処理するための標準のJavaクラスは、おそらくこれを自動的に処理します。

バイトデータにBOMがない場合、これはかなり難しくなります。.NETクラスは統計解析を実行してエンコーディングを試してみることができますが、これはあなたがテキストデータを扱っています(どのエンコーディングが使用されたか分かりません)。

入力データの形式を制御できる場合は、バイトオーダーマークが含まれていることを確認することをお勧めします。

+1

Javaは自動的にBOMを挿入せず、デコード時にBOMを削除しません。 – McDowell

+1

Erk、JavaはUTF-8用のBOMを扱っていないと言わなければなりません。 UTF-16/UTF-32の場合とそうでない場合は、選択したエンコーディングの仕組みによって異なります:http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html – McDowell

3

質問は、文字列とバイナリデータの間に根本的な違いがあることを前提としています。これは直感的には間違いありませんが、その違いを正確に定義することは不可能です。

Java文字列は、(ほとんど)2 ** 16 Unicode基本コードポイントの1つに対応する16ビット数のシーケンスです。しかし、これらの16ビットの「文字」を見ると、それぞれが整数、バイトのペア、ピクセルなどを等しく表すことができます。ビットパターンには、それが何を表しているかについての本質的なものはありません。

ここで、UTF-8でエンコードされたTEXTと任意のバイナリデータを区別する方法を質問したとします。これは役に立ちますか?理論的には、書かれたテキストをエンコードするビットパターンは数字のシーケンスでもあり得るからです。 (本当にここに何を意味するのか、「任意」とは言い難い数は「任意」であるならば、あなたはどのようにテストするを教えてもらえます。?)

我々がここでできる最善のは以下の通りです:

  1. バイトが有効なUTF-8エンコーディングであるかどうかをテストします。
  2. デコードされた16ビットの数量がすべて正当な「割り当て済みの」UTF-8コードポイントであるかどうかをテストします。 (一部の16ビット数は不正(例:0xffff)で、他の文字は現在どのキャラクターにも対応していません。)しかし、テキスト文書が実際に割り当てられていないコードポイントを使用している場合はどうなりますか?
  3. Unicodeコードポイントが、ドキュメントの想定される言語に基づいて期待する「プレーン」に属するかどうかをテストします。しかし、どのような言語を期待するのか、複数の言語を使用する文書があるのか​​わからない場合はどうすればよいでしょうか?
  4. テストは、コードポイントのシーケンスで、単語、文などのように見えます。しかし、埋め込まれたテキストシーケンスを含むような "バイナリデータ"があればどうでしょうか?

要約すると、デコードに失敗した場合、バイトシーケンスは間違いなくUTF-8ではないことがわかります。それ以外に、もしあなたが言語を前提とするならば、おそらくまたはではないかもしれないと言うことができます。 UTF-8エンコードされたテキスト文書です。

IMO、あなたができることは、プログラムがこの決定を下す必要がある状況に陥るのを避けることです。それを避けることができない場合は、プログラムが間違っているかもしれないことを認識してください。思考と苦労によって、あなたはそうすることはできませんが、確率は決してゼロにならないでしょう。ここで

4

はもともと書かれたようW3C site

static boolean looksLikeUTF8(byte[] utf8) throws UnsupportedEncodingException 
{ 
    Pattern p = Pattern.compile("\\A(\n" + 
    " [\\x09\\x0A\\x0D\\x20-\\x7E]    # ASCII\\n" + 
    "| [\\xC2-\\xDF][\\x80-\\xBF]    # non-overlong 2-byte\n" + 
    "| \\xE0[\\xA0-\\xBF][\\x80-\\xBF]   # excluding overlongs\n" + 
    "| [\\xE1-\\xEC\\xEE\\xEF][\\x80-\\xBF]{2} # straight 3-byte\n" + 
    "| \\xED[\\x80-\\x9F][\\x80-\\xBF]   # excluding surrogates\n" + 
    "| \\xF0[\\x90-\\xBF][\\x80-\\xBF]{2}  # planes 1-3\n" + 
    "| [\\xF1-\\xF3][\\x80-\\xBF]{3}   # planes 4-15\n" + 
    "| \\xF4[\\x80-\\x8F][\\x80-\\xBF]{2}  # plane 16\n" + 
    ")*\\z", Pattern.COMMENTS); 

    String phonyString = new String(utf8, "ISO-8859-1"); 
    return p.matcher(phonyString).matches(); 
} 

からUTF-8「バイナリ」正規表現を使用する方法ですが、正規表現をバイト配列に使用されることを意味しているが、あなたはそれを行うことはできませんJavaの正規表現を使用します。ターゲットはCharSequenceインターフェイスを実装するものでなければなりません(char[]もあります)。 byte[]をISO-8859-1としてデコードすると、各charの元の配列の対応するバイトと同じ符号なし数値を持つStringが作成されます。

他の人が指摘したように、このようなテストは唯一byte[]はそれを行うことを、UTF-8のテキストをない含まれる可能性があなたを伝えることができます。しかし、正規表現は非常に網羅的です。生のバイナリデータがそれを過ぎ去る可能性は極めて低いようです。正規表現はNULと決して一致しないので、すべての0の配列でも一致しません。唯一の可能性がUTF-8とバイナリであれば、私はこのテストを信頼しています。

あなたがいる間、UTF-8 BOMがあればそれを取り除くことができます。それ以外の場合、UTF-8 CharsetDecoderはテキストのように渡します。

いつものバイトシーケンスが非常に少ないため、UTF-16ははるかに難しくなります。私がオフハントと考えることができる唯一のものは、代理の低い相手がいない高位の代理人です。逆の場合もあります。それを超えて、特定のシーケンスが有効かどうかを判断するためには、いくつかのコンテキストが必要です。あなたはキリル文字の後に中国語の表意文字が続き、その後にスマイリーフェイスのかわいい表記があるかもしれませんが、それは完全に有効なUTF-16でしょう。

-1

私はマイケルがうまく説明したと思います。in his answerこれは、バイト配列にすべての有効なutf-8シーケンスが含まれているかどうかを調べる唯一の方法です。私はPHPで次のコードを使用してい

function is_utf8($string) { 

    return preg_match('%^(?: 
      [\x09\x0A\x0D\x20-\x7E]   # ASCII 
     | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
     | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
     | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
     | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
     | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
     | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
     | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
    )*$%xs', $string); 

} 

は、元の質問ではW3.org

+0

"whatアプローチはJavaで " –

0

からそれを撮影:私はバイト配列をJavaでUnicode文字列が含まれているかどうかを確認することができますどのように?; Java Unicodeという言葉は基本的にUtf16 Code Unitsを指していることがわかりました。私はこの問題を自分で解決し、このタイプの質問を誰かが心に留めて助けてくれるコードをいくつか作成しました。

私は2つの主要なメソッドを作成しました.1つはUtf-8コードユニットを表示し、もう1つはUtf-16コードユニットを作成します。 Utf-16 Code Unitsは、JavaとJavaScriptで遭遇するものです...一般的には "\ ud83d"の形式で表示されます

コード単位と変換の詳細については、

https://r12a.github.io/apps/conversion/

ここ

コードがある...

byte[] array_bytes = text.toString().getBytes(); 
    char[] array_chars = text.toString().toCharArray(); 
    System.out.println(); 
    byteArrayToUtf8CodeUnits(array_bytes); 
    System.out.println(); 
    charArrayToUtf16CodeUnits(array_chars); 


public static void byteArrayToUtf8CodeUnits(byte[] byte_array) 
{ 
    /*for (int k = 0; k < array.length; k++) 
    { 
     System.out.println(name + "[" + k + "] = " + "0x" + byteToHex(array[k])); 
    }*/ 
    System.out.println("array.length: = " + byte_array.length); 
    //------------------------------------------------------------------------------------------ 
    for (int k = 0; k < byte_array.length; k++) 
    { 
     System.out.println("array byte: " + "[" + k + "]" + " converted to hex" + " = " + byteToHex(byte_array[k])); 
    } 
    //------------------------------------------------------------------------------------------ 
} 
public static void charArrayToUtf16CodeUnits(char[] char_array) 
{ 
    /*Utf16 code units are also known as Java Unicode*/ 
    System.out.println("array.length: = " + char_array.length); 
    //------------------------------------------------------------------------------------------ 
    for (int i = 0; i < char_array.length; i++) 
    { 
     System.out.println("array char: " + "[" + i + "]" + " converted to hex" + " = " + charToHex(char_array[i])); 
    } 
    //------------------------------------------------------------------------------------------ 
} 
static public String byteToHex(byte b) 
{ 
    //Returns hex String representation of byte b 
    char hexDigit[] = 
      { 
        '0', '1', '2', '3', '4', '5', '6', '7', 
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 
      }; 
    char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; 
    return new String(array); 
} 
static public String charToHex(char c) 
{ 
    //Returns hex String representation of char c 
    byte hi = (byte) (c >>> 8); 
    byte lo = (byte) (c & 0xff); 

    return byteToHex(hi) + byteToHex(lo); 
} 
関連する問題