技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

java:絵文字を含む文字列を1文字ずつ切り出す

🗿←こんな感じの絵文字を資料中に使うのが今の職場で流行ってます。

そういえば実務で絵文字を取り扱うシステムに携わったことがなかったので、興味本位で調べてみました。

ついでに、絵文字を含む文字列を1文字ずつ切り出すjavaのサンプルコードも作りました。

 

【絵文字の定義】

絵文字は符号化文字集合Unicode」で定義されており、Unicode文字符号化方式である「UTF-8」「UTF-16」等で使用することができる。

(「符号化文字集合」とは「文字」と「文字に割り当てた番号」の対応表、「文字符号化方式」とは「文字に割り当てた番号」と「実際にコンピュータが扱う数字」の対応表のことである)

なお、「UFT-16」は狭義の「Unicode」として呼ばれることもある。

 

Unicodeは元々1~2バイト文字を定義していたが、世界中の文字を取り扱いたいという要望に応えるために4バイト文字を拡張領域として定義した。

絵文字は、この拡張領域に含まれる。

4バイト文字は、「上位サロゲート(2バイト)+下位サロゲート(2文字)」の組み合わせで定義される。

「上位サロゲート」は0xD800~0xDBFF(1024通り)、「下位サロゲート」は0xDC00~0xDFFF(1024通り)で定義され、何れも2バイト文字では使用しないコードであるため、表現が衝突することはない。

 

4バイト文字は定義当時は実際に扱われることが少なかったが、日本の携帯の絵文字の普及により一般的に使われるようになり、Webシステム等では無視できない存在となった。

 

【サンプルコード】

・コード

public class Sample {

  public static void main(String args[]){

    // 引数から「🚅Unicode🌏絵文字で遊んでみよう😮」を取得し表示→化ける

    System.out.println("引数から取得:"+args[0]);

    // 変数で直接4バイト文字込みの文字列を定義し表示→化けない

    String str = "🚅Unicode🌏絵文字で遊んでみよう😮";

    System.out.println("変数から取得:"+str);

    // 何も考えず1文字ごと文字と文字コードを出力→4バイト文字は2文字扱い

    for (int i = 0; i < str.length() ; i++) {

      int code = (int)str.charAt(i);

      String hex = Integer.toHexString(code);

      System.out.println((i + 1) + "番目の文字:" + str.charAt(i) + " 16進数:" + hex);

    }

    // サロゲート文字で4バイト文字を判定し、正しく1文字ずつ切り出す

    String upperSurStart = "d800";

    String upperSurEnd = "dbff";

    int fourByteMojiCount = 0;

    for (int i = 0; i < str.length() ; i++) {

      int mojiPos = i+1-fourByteMojiCount;

      int code = (int)str.charAt(i);

      String hex = Integer.toHexString(code);

      String strOneMoji = "";

      if (hex.compareTo(upperSurStart)>=0 && hex.compareTo(upperSurEnd)<=0) {

        strOneMoji = str.substring(i,i+2);

        i++;

        fourByteMojiCount++;

      } else {

        strOneMoji = str.substring(i,i+1);

      }

      System.out.println(mojiPos + "番目の文字:" + strOneMoji);

    }

  }

}

 

・出力

引数から取得:??Unicode??絵文字で遊んでみよう??

変数から取得:🚅Unicode🌏絵文字で遊んでみよう😮

1番目の文字:? 16進数:d83d

2番目の文字:? 16進数:de85

3番目の文字:U 16進数:55

4番目の文字:n 16進数:6e

5番目の文字:i 16進数:69

6番目の文字:c 16進数:63

7番目の文字:o 16進数:6f

8番目の文字:d 16進数:64

9番目の文字:e 16進数:65

10番目の文字:? 16進数:d83c

11番目の文字:? 16進数:df0f

12番目の文字:絵 16進数:7d75

13番目の文字:文 16進数:6587

14番目の文字:字 16進数:5b57

15番目の文字:で 16進数:3067

16番目の文字:遊 16進数:904a

17番目の文字:ん 16進数:3093

18番目の文字:で 16進数:3067

19番目の文字:み 16進数:307f

20番目の文字:よ 16進数:3088

21番目の文字:う 16進数:3046

22番目の文字:? 16進数:d83d

23番目の文字:? 16進数:de2e

1番目の文字:🚅

2番目の文字:U

3番目の文字:n

4番目の文字:i

5番目の文字:c

6番目の文字:o

7番目の文字:d

8番目の文字:e

9番目の文字:🌏

10番目の文字:絵

11番目の文字:文

12番目の文字:字

13番目の文字:で

14番目の文字:遊

15番目の文字:ん

16番目の文字:で

17番目の文字:み

18番目の文字:よ

19番目の文字:う

20番目の文字:😮

 

・余談

引数から文字列を与えた時は4バイト文字が「??」に化けた。

引数はUnicodeではないのだろうか?

(実務ではフォームやファイルが入力となり、そこで文字コードの指定ができるので、別に気にする必要はないのだが…)

 

【その他(MySQLについて)】

MySQLは5.5.3以降でないと4バイト文字を取り扱えない。

 (5.5.3以降では「utf8mb4」という文字コードで取り扱える)

--------------------------

追記

ソースコードを書くことが多くなってきたので、PC版のデザインを横幅なものに変更しました。