エキサイト株式会社 メディアサービスエンジニアのしばたにえんです。
早速以下のコードを見てください
void getStringLength() { String str = "𩸽"; System.out.println(str.length()); }
実はこの結果は2です。 原因はサロゲートペアにあります。
サロゲートペアとは
通常、Unicodeでは1文字あたり2バイトのデータ量を使います。 2バイトですから65536通り(0x0000~0xFFFF)のビットを表現できます。 この約6万字で世界中の文字を表現しようというのがUnicodeの本来の思想でした。 ところが、近年、Unicodeに組み込みたいという文字の要望がいろいろと増えてきました。 結果的に従来の2バイト(65536文字)では文字が足りない状況になってしまったのです。 そこで、解決策としてサロゲートペアという方法が導入されました。 「1文字=2バイト」の基本は維持しつつ、一部の文字については「1文字=4バイト」にする方法です。
void getCharLength() { String str = "𩸽"; System.out.println(Integer.toHexString(str.charAt(0))); System.out.println(Integer.toHexString(str.charAt(1))); } // 実行結果 d867 de3d
"𩸽"
は見た目上は1文字ですが、サロゲートペア文字で4バイトで表した文字でchar2つで表されます。length()はchar1つにつき1とカウントされるため値が違ったのです。
本当の文字数を取得する
void getRealLength() { String str = "𩸽"; System.out.println(str.codePointCount(0, str.length())); } // 実行結果 1
codePointCountメソッドでは正しく1とカウントできていることが確認できます。 codePointCountメソッドでは、文字列をカウントする際の開始/終了位置が必須なので、文字列全体をカウントするには、それぞれ0(先頭)、str.length(末尾)を指定しています。
length()を使う際は気をつけましょう。