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

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

ただいまの
回答率

90.40%

  • Java

    14807questions

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

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

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 6,958
退会済みユーザー

退会済みユーザー

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以外と判定
}

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

0

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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種類ほどサンプルとなる関数を作ってみました。

import java.util.Arrays;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.charset.CharacterCodingException;

public class EncodeChecker {
  public static boolean check1(byte[] bytes, Charset cs) {
    return Arrays.equals(new String(bytes, cs).getBytes(cs), bytes);
  }
  public static boolean check1(byte[] bytes) {
    return check1(bytes, StandardCharsets.UTF_8);
  }

  public static boolean check2(byte[] bytes, Charset cs) {
    return cs.encode(cs.decode(ByteBuffer.wrap(bytes)))
      .equals(ByteBuffer.wrap(bytes));
  }
  public static boolean check2(byte[] bytes) {
    return check2(bytes, StandardCharsets.UTF_8);
  }

  public static boolean check3(byte[] bytes, Charset cs) {
    try {
      cs.newDecoder().decode(ByteBuffer.wrap(bytes));
      return true;
    } catch (CharacterCodingException e) {
      return false;
    }
  }
  public static boolean check3(byte[] bytes) {
    return check3(bytes, StandardCharsets.UTF_8);
  }
}


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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Java

    14807questions

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