2010-11-20-01-文字コードの話 - 17 - project-enigma

2010-11-20-01-文字コードの話 - 17

>> Site top >> weblog >> 月別アーカイブ >> 2010年11月のlog >> 2010-11-20-01-文字コードの話 - 17

最終更新日付:2013/12/31 07:35:47


文字コードの話 - 17

2010 年 11 月 20 日

「お開きにする」と書いたにも関わらず、性懲りもなく続きを書いている。

このライブラリを使ったプログラミングをしていて、少しばかり面倒な事態に遭遇した。それは、文字列リテラルを使ったコピーや比較だ。たとえば以下のような。

if( enc.StrCmp( p, "abc" ) == 0 )
    // do something

見たところ、比較対象の文字列リテラルは ASCII だし、なんの問題もないように思える。Shift_JIS でも euc-jp でも、utf-8 でも大丈夫のはずだ‥‥‥と書けばわかるだろう。そう、上記のコードは utf-16 や utf-32 では意図したとおりには動作しないのだ。あ、EBCDIC の一族でも動作しないが、あれは文字コードと呼ぶべきものじゃないからいいよね。

話を戻そう。文字列を比較するなら、両者のエンコーディングは揃えなければならない。先のコードのように比較の対象が文字列リテラルの場合、複数のエンコーディングに対応するには複数の文字列リテラルを用意する必要があるわけだ。良く使われているエンコーディングでは ASCII 部分の表現方法は同じだが、utf-16 などではそうはいかない。

ライブラリを利用するアプリケーション側でこの問題に対処しようとすると、エンコーディングの種類をパラメータとしてとる文字列リソーステンプレートを作成することになる。というか、以前はそうしていた。しかし、アプリケーション内部で使用される文字列リテラルというのは ASCII が多いものだし、文字列リソーステンプレートというのはある程度規模の大きなアプリケーションでなければ大袈裟に感じられてしまうものだ。

そこで、ASCII 文字列を使った比較やコピーを独立したメソッドとして提供することを考える。一般的な使用を考える限り、NULL 終端している ASCII 文字列、つまりいわゆる ASCIZ 文字列を対象とするような感じで良いだろう。つまり CmpWithASCIZ とかCpyFromASCIZ みたいなメソッドを提供する、という考え方だ。しかし、これをライブラリとして提供する必要があるかどうか。しばらくは考える必要があるだろう。

ついでにもうひとつ。以下のコードは何がマズいだろうか。

template <typename ENC>
void Foo( const ENC& enc, char* pBuf, const char* pSrc, int len ) {
    enc.StrNCpy( pBuf, pSrc, len );
    pBuf[len] = 0;
}

答えは、pBuf[len] = 0; という部分だ。なぜなら、どのようなエンコーディングでも1バイト幅の NULL 文字で終端させられるという前提があるからだ。これも、やはり utf-16 のようなエンコーディングでは良くない前提だ。しかし、現状では Iterator を使って以下のように書くしか方法がない。

template <typename ENC>
void Foo( const ENC& enc, char* pBuf, const char* pSrc, int len ) {
    enc.StrNCpy( pBuf, pSrc, len );
    *(enc.GetIterator( pBuf + len )) = 0;
}

これもなんだかイマイチだ。しかし、エンコーディングクラスに SetNullChar みたいなのを追加するのもなんだか面白くない。これまたしばらく悩むことになるだろう。

 

コメント

このページにコメントする

 

このページのタグ

Page tag : 開発

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.