Personal tools
You are here: Home ブログ 井上 UTF8の文字数を数える手法の検討
« December 2010 »
Su Mo Tu We Th Fr Sa
      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 27 28 29 30 31  
Recent entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
Categories
カテゴリなし
 
Document Actions

UTF8の文字数を数える手法の検討

AirOneの内部文字列のエンコーディングはUTF8です。

内部文字列のエンコーディングの候補は、事実上、次の4パターンだと思います。

  • utf8
  • ucs2
  • (locale依存の)マルチバイト
  • wchar_t

CSI(CodeSet Independent)の観点での推奨はwchar_tです。しかし、Windowsでのwchar_tの扱いに不安、と言うより、今はともかく5年前は、GNU/LinuxのGNU libcでもwchar_tは不安、という状況だったのでwchar_tの選択肢は消えました。

ucs2の選択はWindows限定であれば、ありかもしれません(WCHARを使う)。しかし、この選択は見かけほど簡単ではありません。外部ライブラリの多くはWCHARに依存したAPIは持ちません。これらのAPI呼び出しの時に、WCHARとの相互変換が必要になります。エンコーディングの変換の必要箇所が増えるほど、バグを埋め込む可能性も高くなります。

外部ライブラリを考慮すると、結局、内部文字列はchar*で持つのが妥当という判断をしました。本当の文字列処理(ソートや検索など)を外部(WebブラウザやXSLT。下記参照)に追い出しているからこそできる芸当かもしれませんが。

選択肢はUTF8か(locale依存の)マルチバイトになりました。locale依存のマルチバイトは、正しく国際化APIを使っている限り問題は無いのですが、高度な政治的判断でUTF8にしました。

最近、「UTF8文字列の文字数を数えるAPIはありますか」、と質問されました。

今までUTF8の文字数を数える必要がありませんでした。 上に書いたように、UI周りはWebブラウザ(IEコンポーネントやFirefox)に任せているので、AirOne本体が文字数を意識する場面が無かったことと、HTML生成の多くがXSLT任せ(libxslt)だったので、やはりAirOne本体が文字数を意識する必要が無かったからです。

UTF8文字列の文字数を数えるには次の方法があります。

  • mblen(3)やmbrlen(3)のマルチバイト用標準APIを使う
  • mbstowcs(3)でwchar_tに変換してから数える
  • iconvでUCS2(or UCS4)に変換してから数える
  • 自前でUCS2(or UCS4)に変換してから数える
  • 自前でUTF8用に実装する

国際化プログラミングの教えは、「文字列処理にはAPIを使え」、であり、更に言えば「標準APIを使え」、です。この観点で正しい手法は、1番目か2番目の手法です。しかし、これらはlocaleに依存します。文字列のエンコーディングがUTF8と分かっている時には、一般的すぎて大げさに感じます。そもそも、localeによらず内部エンコーディングをUTF8に固定している時点でCSIに反しているので、大げさ、と批判するのはお門違いです。

選択肢は、UCS2に変換するか、UTF8のまま数えるか、です。自分の経験からの国際化プログラミングの鉄則は、「エンコーディングの変換にバグが宿る」です。入ってくる所(ファイル、ネットワーク、ユーザ入力など)と出ていく所でだけエンコーディングの変換をして、プログラムの中では内部エンコーディングを一貫すべき、と言うのが結論です。

と言うことで、UTF8のまま文字数を数えることにしました。

GLib(http://www.gtk.org)から以下のコードを拝借しました。pはUTF8文字の先頭バイトを指している必要があります。

/* Array of skip-bytes-per-initial character.
 */
GLIB_VAR const gchar * const g_utf8_skip;
#define g_utf8_next_char(p) (char *)((p) + g_utf8_skip[*(guchar *)(p)])

static const gchar utf8_skip_data[256] = {
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
const gchar * const g_utf8_skip = utf8_skip_data;
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/utf8-handling/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.