Posts Tagged ‘UTF-8’

絵文字を含むNSStringの正確な文字数をカウントする

 iPhone/iPad のキーボード設定で「絵文字」というキーボードを追加すると、ガラケーよろしく絵文字を入力できるようになる。なので、何も考えないとUITextFieldなどに絵文字を入力されてしまう可能性がある。ここでアプリの仕様上、絵文字を許容するかしないかという議論は当然起こるが、許容したくないというケースはひとまず置いといて、許容する場合のトピックを取り上げる。

 絵文字も他の文字と同様UTF-8であるようだが、絵文字の中には4バイトで表現されるものもあるようで、その4バイトの絵文字を含んだ文字列は [str length] で得られる文字数が狂ってしまうのだ。そうなるとバリデーションとして文字数制限を設ける場合にうまくない。

 この現象はどうやらNSStringクラスのUTF-8の取り扱いに原因があるようだが、不具合だと認識されていれば将来的にSDKの方で対応される可能性がある。それまでは次のような関数で凌ぎたいと思う。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (NSUInteger) actualUtf8StringSize:NSString str {
     const char* cstr = [str UTF8String];
     int len = strlen(cstr);
     NSUInteger count = 0;
     unsigned char c;
     for (int i = 0; i < len; i++) {
          c = (unsigned char)cstr[i];
          if (0x00 <= c && c <= 0x7F) {
               ;
          }
          else if (0xC2 <= c && c <= 0xDF) {
               i += 1;
          }
          else if (0xE0 <= c && c <= 0xEF) {
               i += 2;
          }
          else if (0xF0 <= c && c <= 0xF7) {
               i += 3;
          }
          else {
               continue;
          }
          ++count;
     }
     return count;
}

 これはUTF-8の性質を利用して文字数をカウントしている。UTF-8は文字の1バイト目でその文字が何バイトかを示している。なので、バイト列を先頭から調べて行き、文字のバイト数分スキップしながらカウンタを増加している。ひとつ留意したいのは、バイト列から1バイト取得する時に char 型ではなく unsigned char 型の変数に代入することだ。C言語では常識の範疇だが、慣れていないと見落としやすい。

アーカイブ