質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

3回答

17723閲覧

java:バイト配列の文字コード判定

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2015/12/22 07:51

Javaで実装したHTTP通信処理において受信したバイト配列の文字コードがUTF-8か簡単に判定できる方法はありませんか。
juniversalchardet等のOSSは利用せず、UTF-8かどうか判定したいと考えています。

比較する情報が文字列の場合、以下のロジックで判定できるという記事を見つけましたが、どうにも腑に落ちません。
アスキーコードのみで作成された文字列の場合、UTF-8以外(shift-JIS)でもUTF-8と判定されてしまう気がしています。

String hoge = "hogehoge"
String utf = new String(hoge.getBytes("UTF-8"), "UTF-8");

if(hoge.equals(utf)){
// UTF-8と判定
} else
// UTF-8以外と判定
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ASCIIはUTF-8のサブセット(一部分であるという意味)です。そして、ASCIIはShift_JISのサブセットでもあります。集合で言うと、
ASCII ⊂ UTF-8
ASCII ⊂ Shfit_JIS
のような関係です。ASCIIの文字はUTF-8としてもShift_JISとしてもどちらで解釈しても正しいです。ですので、ASCIIの文字だけで構成されているバイト列が本来どのエンコードとして書かれたものなのかを区別する方法はありません。

それはさておき、書かれているコードには問題があります。Stringにしている時点でJavaではUnicode(内部的にはUTF-16)で正しく処理されています。UTF-8はUnicodeに対する完全なマッピングを持っているため、StringをUTF-8のバイト列にする処理が失敗することはありません。また、StringをUTF-8のバイト列に変換後、UTF-8として解釈したときに、元のStringと同じにならないこともありません。比較すべきはStringにする前のbyte配列です。

次に、文字コード指定に"UTF-8"という文字列を使わずにjava.nio.charset.StandardCharsets.UTF_8を使用すべきです。文字コードを表す文字列から該当するエンコードをサポートしているかどうかの処理が省かれる(そして、例外処理も不要)という利点と、"UDF-8"とかスペルミスしていた場合にコンパイル時にわかるという利点があります。

最後に、長い文字列を処理しようとした場合、文字列の生成や文字列全体の比較という重い処理が入ります。わざわざ比較しなくてもデコード自体に失敗したらUTF-8ではないと判断した方がいいです。

これらを踏まえて、3種類ほどサンプルとなる関数を作ってみました。

Java

1import java.util.Arrays; 2import java.nio.ByteBuffer; 3import java.nio.charset.Charset; 4import java.nio.charset.StandardCharsets; 5import java.nio.charset.CharacterCodingException; 6 7public class EncodeChecker { 8 public static boolean check1(byte[] bytes, Charset cs) { 9 return Arrays.equals(new String(bytes, cs).getBytes(cs), bytes); 10 } 11 public static boolean check1(byte[] bytes) { 12 return check1(bytes, StandardCharsets.UTF_8); 13 } 14 15 public static boolean check2(byte[] bytes, Charset cs) { 16 return cs.encode(cs.decode(ByteBuffer.wrap(bytes))) 17 .equals(ByteBuffer.wrap(bytes)); 18 } 19 public static boolean check2(byte[] bytes) { 20 return check2(bytes, StandardCharsets.UTF_8); 21 } 22 23 public static boolean check3(byte[] bytes, Charset cs) { 24 try { 25 cs.newDecoder().decode(ByteBuffer.wrap(bytes)); 26 return true; 27 } catch (CharacterCodingException e) { 28 return false; 29 } 30 } 31 public static boolean check3(byte[] bytes) { 32 return check3(bytes, StandardCharsets.UTF_8); 33 } 34}

check1は文字列を作ってbyet配列にして比較です。あまり変わりません。
check2は文字列を作らずにByteBufferだけで処理しています。String生成が無い分、check1より速い気がします。
check3は単純にdecodeに失敗したらfalseを返すようにしています。比較が無い分、たぶん一番速いです。

投稿2015/12/23 03:35

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

はい、ASCIIの範囲内の文字だけで書かれた文字列は、そのままUTF-8として解釈して問題ありません。

UTF-8は、ASCIIの範囲内の文字をそのまま1バイトで表現しますので、何も違いはありません。むしろ、それが「元からUTF-8だったか、ISO-8859-1のうち半分だけで書かれていたか、シフトJISやEUCで日本語文字がなかったか」など、知るよしもありません(どれで書いても同じバイト列です)。

投稿2015/12/22 08:06

編集2015/12/22 08:10
maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Javaで文字コード簡易判定 に付いているコメントも含めてよく読んでみては?

投稿2015/12/22 07:57

Orlofsky

総合スコア16415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問