ITエンジニアの成長ブログ

ITエンジニアとして行う勉強の発信&日々の生活で体験した楽しいことをゆるく発信

Java内部の文字コードはUTF-16らしい

タイトル通りですが、Java内部の文字コードUTF-16です。

Java関連の記事や書籍で時々見かけていたこの事実ですが、正直それで一体なんなの?という感じでした。

ファイルを読み込みしたり、書き込みしたりする場合に意識しておけばだいたいOKかなという程度の理解で、今までJavaを使っていて特に問題になることはありませんでした。

でも、そういえばUTF-16サロゲートペアの問題あるよな。。。と思い軽く調べました。

UTF-16サロゲートペアとは?

UTF-16は数ある文字コードの1つで、2バイトで文字を表します。しかし、2バイトだと「65535通り」(2の16乗)しか表せないので、実はこれだけでは世界中の文字を表すには十分ではありません。

そのため、表せない文字は既存の2バイトの領域以外の部分を使用して、合計4バイトで表そうみたいな動きになり、その仕組みが「サロゲートペア」ということらしいです(参考の方々の記事がとてもわかりやすかったので、詳細はそちらをどうぞ)。

Javaの文字列クラスStringでサロゲートペアの文字の長さを確認する

ということで、簡単にUTF-16サロゲートペアの話をしました。

そこで、Javaの文字列クラスStringでサロゲートペアの文字の長さはいったいどのように判定されるのか確認してみたいと思います。java.lang.Stringクラスのlength()メソッドでいくつか確認したいと思います。

まずは、アルファベット英語の文字の長さを図ります。「aiueo」はどうなるのか。

public class Sample {
	public static void main(String[] args) {
		String str = "aiueo";
		System.out.println(str + "のlengthは、" + str.length());
	}
}


はい、こちらはString.length()の結果は、もちろん5になりました。別に何も違和感はありません。

「aiueo」のString.length()


次は、日本語のひらがなの長さを図ります。「あいうえお」はどうなるのか。

public class Sample {
	public static void main(String[] args) {
		String str = "あいうえお";
		System.out.println(str + "のlengthは、" + str.length());
	}
}


はい、こちらもString.length()の結果は、5になりました。いい感じですね。

「あいうえお」のString.length()

それでは、やっとサロゲートペアの文字を試してみます。サロゲートペア文字は、「𠀋」で試してみます。「𠀋𠀋𠀋𠀋𠀋」はどうなるのか。

public class Sample {
	public static void main(String[] args) {
		String str = "𠀋𠀋𠀋𠀋𠀋";
		System.out.println(str + "のlengthは、" + str.length());
	}
}


なんと!String.length()の結果が、10になってしまいました。5ではない。。何かしら文字数で処理する実装があった場合、今回のようなサロゲートペアの文字がある場合は障害になってしまうかもしれません。正直知らなかったので驚きました。

「𠀋𠀋𠀋𠀋𠀋」のString.length()

java.lang.StringのlengthメソッドのJavaDocを見てみる

StringのlengthメソッドをJavaDocで見てみると以下のように記載されています。
String (Java Platform SE 8)

String.length()メソッドのJavaDoc

「長さは文字列内のUnicodeコード単位の数に等しくなります。」という記載があります。

今回検証したサロゲートペア文字「𠀋」は、UTF-16エンコーディングすると「D840 DC0B」(16進数)になります。

おそらく、Unicodeコード単位というと「D840」(2Byte)で1文字判定となっているはずなので、今回の文字は1文字(𠀋)だけど、長さが2として判定されるようになっていると思われます。

おわりに

いかがでしょうか。私自身今まで文字列をカウントするような処理をJavaで実装したことはなかったのですが、サロゲートペアを意識しなければならないことを初めて知りました。

Java内部の文字コードUTF-16であることの導入として、今回はこの辺で終わりたいと思います。
最後までお読みいただきありがとうございました。