(08/02/01 ~)

08/02/23

Unicode
 Windows の Unicode (WideString) は Win9x (多分 NT3x / 4.0 も) に於いては UCS-2、2000 / XP / Vista では UTF-16 で表現される。

 UCS-2 は 「Unicode って、完全 2 バイトだよね?」 と言われるアレ。すべての文字は 16bit で表わされる。よって使える文字数は論理的には 65536 文字。ちなみに UCS は Unicode ではない (後述)。

 UTF-16 は基本エリア (BMP = Basic Multilingual Plane) は UCS-2 と完全な互換性があり、加えて Shift_JIS での漢字表現や EMS (Expanded Memory Specification) のような方法でプレーンを拡張し、UCS-2 が論理的に扱える文字数以上の文字を格納できる。BMP にある文字コード未割り当て領域 (プレーン拡張用に使われる) を "サロゲート" と呼び、この領域にあるコードを 2 つ (16bit×2) 使って表わされる文字 (或いは領域) を "サロゲートペア" と呼ぶ。

 つまり、UTF-16 は

 で文字を表現する。

 Shift_JIS 等の漢字領域を DBCS (Double Byte Character Set) / MBCS (Multi Byte Character Set) と言うが、UTF-16 のサロゲートペアははさしずめ "DWCS (Double Word CharacterSet) / MWCS (Multi Word Character Set)" と言ったトコロ。UCS-2 は DBCS ではなく、"SWCS (SingleWord Character Set)" が正解なのだろう。

 勘違いしやすいが、Unicode は最新の規格で 21bit の範囲にある。UCS は Unicode と同列に扱われる文字集合の規格 (Universal Coded-CharacterSet)。UCS-2 は 2byte (固定 2byte = WORD)、UCS-4 は 4byte (固定 4byte = DWORD) の範囲にある...つまり、母集合としては UCS-4 は Unicode よりも大きい。UTF は "Unicode / UCS で表わされる文字の文字コードを変形して扱い易くするための文字符号化方式 (文字エンコーディング) の規格 (Unicode / UCS Transformation Format)" であり、文字集合の規格ではない。すべての Unicode / UCS をフラットに扱うには UTF-32 を使えばいいが、この際には、"1 文字 = DWORD" となってしまう。

Windows と UTF-16
 では、UTF-16 を内部処理で使用している Windows ではすべての文字を表示できるかと言えば、そうとも限らない。サロゲートペアはデフォルト状態では Vista でしか表示できないからだ。2000 / XP でサロゲートペアを表示するためには対応するフォントとレジストリの変更が必要となる。

 Windows 9x に於いては W 系の API はほぼ実装されておらず、Microsoft Layer for Unicode (MSLU) でも使わない限り W 系の API を呼び出すことはできない。例え MSLU を使ったとしても、W -> A 変換でロスしたり、内部 UCS-2 の制限を受けるため "完全 Unicode 対応" は限りなく不可能に近い。

Windows と UTF-8
 有名な UTF-8 は、Shift_JIS をさらに拡張したようなもので、ASCII 部分は 1 バイトで表現でき、それ以外の文字は最大 6 バイト (最新の定義では 4 バイトが上限らしい) で表現する。これこそまさに MBCS と言える。

 これも勘違いしやすいが、"UTF-8 にサロゲートペアは存在しないが、それ以上にややこしい構造になっている" と言うこと。それと、Windows に於いては UTF-16 を内部処理で利用している関係で "間接的にサロゲートペアの影響を受けてしまう" という事。Windows で UTF-8 の話をしている時にサロゲートペアの事を持ち出されても、脊髄反射で 「UTF-8 には関係ねーよ、バーカ」 とか罵ってはいけない。ちなみに、Delphi 2007 にも UTF-8 とサロゲートペアに関する問題が存在する (QC#58386)。


08/02/24

Delphi と Unicode
 昨日の続きで、ここからが本題。

 Delphi は次期バージョンの Tiburón で Unicode 対応となっている。しかし、"現行の Delphi では Unicode が全く扱えない" のかと言えばそうではない。混乱を避けるために先に Delphi の文字列の扱いから説明する。

Delphi の使い分け?
 総合的に考えるに、

 ...と、Delphi を使い分ける必要があるように思える。Delphi 2007 で作成したアプリケーションは基本的に Win9x で動作するのだが、VCL に一部 NT 依存のコードが含まれており、万全を期すのならば、Delphi 7 は要確保と言える。「今更 Win9x はないだろ?」 という方には不要かもしれないが。

 この辺をユーザにちゃんと説明した上であれば "Delphi 7 の再販はアリ" だと思っている...需要がないとは言い切れないのだから。加えて言えば Delphi 2007 の長期的なサポートも一考の価値はあると思う。

 として、別製品にするのもいいのでは?できるものなら 32 / 64bit コンパイラは同一製品が望ましいけれど、VCL の関係もあってそううまくはいかないと思う。それこそ、lib フォルダやパッケージを IDE 上で動的に切り替えられる機構でもない限りは、ね。

ちょっと擁護
 CodeGear がヘタレなのではない。ASCII 圏の人間の作ったものは、どうしても非 ASCII 圏の事は後回しになる (或いは ASCII 圏の利便を図ろうとする)。

 例えば UTF-8。これは 1 バイトの範囲にある文字は ASCII と完全互換だ。ASCII の範囲にある文字だけならば、ASCII だろうが Shift_JIS だろうが、EUC だろうが UTF-8 だろうが同じ処理で済む。「俺らの文字は 1 バイト (或いは 7bit) で済むんだよ、何で Unicode (UCS-2 / UTF-16) で 2 バイトも使わなきゃならんのだ?」 という理屈が見え隠れする。 UTF-8 はサイズの縮小という意味では非 ASCII 圏の人間にも有効ではあるが、他の文字コードセットへの変換時に面倒を伴う...「しわ寄せは全部こっちかよ?」 と言いたくなるのが人情ってもんだ。

 MS だって例外ではない。

 Unicode の問題には "OS の制限" と "開発ツールの制限" の 2 つがあり、議論の内容によって一緒に考えたり分けて考えたりする必要がある。ここを理解しないまま議論するのは非常に危険だ。

コードページとロケール。
 さて、文字コードに関わるもう一つの話をしなくてはならない。コードページとロケールについてだ。

 コードページってのは断りがない限り、"Unicode 対応でないアプリケーションに用いる ANSI 文字列の文字符号化方式(文字エンコーディング)" の事で、文字集合を指すのではない。日本語な ANSI 文字列は Shift_JIS だけれども、Windows の日本語 ANSI 文字列は厳密には "Shift_JIS を拡張した CP932" が正しい。プログラミングするなら GetACP() 或いは GetOEMCP() という API で取得できる。

 ロケールというのはお住まいの地域の事。国 / 地域番号とでも言えばいいか。日本のロケール ID は 0x0409 プログラミングするなら GetUserDefaultLCID() という API で取得できる。実はロケールには複数あるのだが (システム / ユーザ / スレッド...)、話がまたややこしくなるので一般に言う所の "現在のロケール" という前提にしておく。

 もう、お分かりかとは思うけど、ロケールとコードページは "関係はあるけど別物"。同じ国の中に異なる言語が存在する事だってあるのだから、ロケールからコードページは特定できない事になる。ややこしいのは OEM コードページという奴。これは Microsoft が管理していないコードページで、日本の CP932 だって元々は OEM コードページだった。MS-DOS の頃、PC / AT と PC-98 で "同じ Shift_JIS なのに違う文字 (機種依存)" だったのは、OEM コードページだったため。Microsoft が管理していないコードページは、同じコードでもベンダによって表示される文字が違う事がある。それと、日本の場合 GetOEMCP() では CP932 が返らないかといえばそうではなく、ちゃんと CP932 が返ってくる。

 さて、そろそろ Delphi にまつわる話をしよう。"[Delphi-ML:90290] Delphi 2007 の TLabel の文字化け" でフォントの Charset の話をしているけれど、中村さんも僕もロケールには言及していない。先に書いたように、この話でロケールとコードページには因果関係はないからだ。それに、DEFAULT_CHARSET が正しく動作しないのはある意味仕方がないのだ...別に日本語の事だけを考えている訳じゃない。

 最近の Delphi でオブジェクトインスペクタに列挙される Charset は OEM コードページ となっているので (<- これは勘違いであり嘘。実際のトコロは後述) は、例えば韓国なんかだと HANGEUL_CHARSET (CP949) と JOHAB_CHARSET (CP1361) という 2 つのコードページが使える事になる。

 特別な処理が無い場合にはコンポーネント等の Font の初期値は "Delphi のデフォルトフォント" を参考にしている (多分)。では、Delphi のデフォルトフォントはどうやって求められているのか?

 普通の考え方なら、

  1. GetACP() / GetOEMCP() でコードページを取得。
  2. デフォルトフォントにはそのコードページを持つフォントと Charset を指定する (コードページによって決め打ちで)。
 たったこれだけの事だが、実際には違う。
  1. デフォルトフォントの初期値を "MS Sans Serif"、DEFAULT_CHARSET とする。
  2. ロケールが "FarEast" 以外なら抜ける。
    なお、ここではロケールの取得に GetSystemMetrics (SM_DBCSENABLED) を使っている。
  3. システムフォント情報を GetTextMetrics() で取得。
  4. フォント情報から Charset を取得。これをデフォルトの Charset とする。
  5. もし、Charset が SHIFTJIS_CHARSET なら、デフォルトフォントを "MS Pゴシック"、SHIFTJIS_CHARSET に。
 これが Delphi 7 の場合。これだと、VCL が同一ソースの場合には中国や韓国、台湾ではデフォルトフォント名が設定されない事になってしまう。この部分のローカライズがなかったのだとしたら、DEFAULT_CHARSET には、潜在的な問題があったという事になる。では Delphi 2007 では?
  1. デフォルトフォントの初期値を "MS Sans Serif"、DEFAULT_CHARSET とする。
  2. プラットフォームが Win32 でシステムフォント情報で Charset が SHIFTJIS_CHARSET ならばデフォルトフォント名を "Tahoma" に設定。
  3. [HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes] を参照、
    デフォルトフォント名を "MS Shell Dlg 2" で示されるフォント (XP 日本語版等では "Tahoma") に設定。
 何故こういうロジックになってしまうのか...orz。これだと今度は、  これでは、DEFAULT_CHARSET は意味をなさない気がする。中村さんとの話で違和感を感じたのは、恐らく手持ちの Delphi の違いによるものだろうと思う (不思議に思って Delphi 7 / 2007 の Source フォルダを確認したのは ML 投稿の後)。

 そして重要なのは、日本に於いては僕の示した "普通の考え方" でいいのだろうが、"一つの国で複数のコードページを持つ場合" にはそうとばかりも言えない、という事だ。現状では、「リポジトリを用いて回避しろ」 としか言えない...もちろんこれは日本国内に限った話ではない。

 なお、この話題は "[delphi.japanese:TFont.Charset の DEFAULT_CHARSET の扱いについて]" として NG に問題提起してあるので、「実際のトコロどうすべきなのか?」というアイデアをお持ちの方には是非議論に加わって頂きたいと思っている。


08/02/26

コードページとフォントの Charset の関係。
 ちょっと訂正。

 うは、TFont.Charset はGetACP()/GetOEMCP()だけじゃ処理できないじゃん。

 なーるホド。オブジェクトインスペクタで VIETNAMESE_CHARSET が選択できないのも GetACP() / GetOEMCP() でコードページを取得できないからなのだろうな。

case GetACP of
  874: 
    begin
      DefFont.Name := '???';
      DefFont.Charset := THAI_CHARSET;
    end;  
  932: 
    begin
      DefFont.Name := 'MS Pゴシック';
      DefFont.Charset := SHIFTJIS_CHARSET;
    end;  
  936:
    begin
      DefFont.Name := '???';
      DefFont.Charset := GB2312_CHARSET;
    end;  
  949:
    begin
      DefFont.Name := '???';
      DefFont.Charset := HANGEUL_CHARSET;
    end;  
  950:
    begin
      DefFont.Name := '???';
      DefFont.Charset := CHINESEBIG5_CHARSET;
    end;  
  1250:
    begin
      DefFont.Name := '???';
      DefFont.Charset := EASTEUROPE_CHARSET;
    end;  
  1251:
    begin
      DefFont.Name := '???';
      DefFont.Charset := RUSSIAN_CHARSET;
    end;  
  // LATIN (Include ANSI)
  1252:
    begin
      DefFont.Name := '???';
      DefFont.Charset := ANSI_CHARSET;
    end;  
  1253:
    begin
      DefFont.Name := '???';
      DefFont.Charset := GREEK_CHARSET;
    end;  
  1254:
    begin
      DefFont.Name := '???';
      DefFont.Charset := TURKISH_CHARSET;
    end;  
  1255:
    begin
      DefFont.Name := '???';
      DefFont.Charset := HEBREW_CHARSET;
    end;  
  1256:
    begin
      DefFont.Name := '???';
      DefFont.Charset := ARABIC_CHARSET;
    end;  
  1257:
    begin
      DefFont.Name := '???';
      DefFont.Charset := BALTIC_CHARSET;
    end;  
else
  case GetOEMCP of
    // KOREA(JOHAB)
    1361:
      begin
        DefFont.Name := '???';
        DefFont.Charset := JOHAB_CHARSET;
      end;
  else
    case GetUserDefaultLCID of
      // VIETNAM
      $042A:
        begin
          DefFont.Name := 'Tahoma';
          DefFont.Charset := VIETNAMESE_CHARSET;
        end;
    else
      DefFont.Name := 'MS Sans Serif';
      DefFont.Charset := GetDefFontCharset;
    end;  
  end;
end;  

 それじゃ、こんな感じになるのかな?これで、ベトナムも(殆ど)OKだね...gặp sau nhè

ちなみに。
 Tiburón とかの ó のように声調記号のある文字の入力には "UniKey" を使っています。以前、ベトナムへ出張した際には重宝しました。以下、実際の使い方です。

  1. UniKey をインストール。
  2. ダブルクリックで起動して常駐させる。
  3. Mở rộng〕ボタンを押す。
  4. "Hệ thống" にある "Vietnamese interface" のチェックを外すとインターフェイスが英語になる。
  5. 〔Default〕ボタンを押す (3~5 は初回時のみの設定)。
 〔Ctrl〕+〔Shift〕 でベトナム語入力モードになりますので、ここで "Tiburosn" とタイプすれば "Tiburón" と表示されます。記号とタイプ方法は以下の通りです。

 ベトナム語の入力方式にはイロイロありますが、ここでは TELTEX 方式を紹介しています。"ặ" なんて文字もある訳で、これは "awj" または "ajw" とタイプします。「Tiburón のóだけのために UniKey をインストールするのは大袈裟すぎる」 って方は "Online Keyboard for Vietnamese" で適当にキーを押してコピペして下さい...まぁ、このページからコピペするってのもアリなんですが (^^;A

 なお、正しくベトナム語と日本語を混在できるフォントは

 だけです。

 ...ですが、実際にやってみると "MS ゴシック" 等でも表示できるように見えます。しかし (詳しい理由は述べませんが) 一部の文字だけがボールドになります。日本語とベトナム語を混在させる場合にはできるだけ "Arial" や "Tahoma" を使うようにして下さい。または、ベトナム語の箇所だけフォントを変更するようにして下さい (Word や Excel の場合)。


08/02/28

パンが無ければお菓子を(以下略)
 雑談にコメントできなきゃ、掲示板を(以下略)。専用スレッドを用意してみましたので、昨今の雑談にツッコミを入れたい方はどうぞ (メアドは必須ではありません)。目印としてフサを置いておきました。掲示板の注意書きにもありますが、REMOTE_HOST が見えますので自演したい場合には充分注意を払ってからやって下さいね。

 荒れない程度にマターリやれれば、よろしいかと...。


08/02/29

"デベロッパーキャンプ、ご参加ありがとうございました。" を検証する。
 私は先のデブキャンに参加する事が叶いませんでしたが、こうして資料の提示があるのは喜ばしい事です...地方に居ながらにして、重要な情報が得られるのですから。

 [String は UnicodeString にマップ]

 [文字のインデックス化と通常の文字列処理に変更はない]

 サマリーに関するツッコミは以上です。G2 セッションの新しい資料が入手でき次第、追って検証を行いたいと思います。

彼からの Mail
 溜まってますねー。

こうさ、カウパーが乾燥して癒着した下着と尿道が剥がされる瞬間の切ない痛みを感じる時、いつも庵寿と厨子王のその後に想いを馳せる。

 織姫と彦星でもいいのではないでしょうか?

今便所なんだけどさ、座った瞬間の屁音が「ピキュン」っていうか「フィキュッ」っていうか、なんかその辺の萌えキャラの呻き声みたいだったんで、俺もだいぶ丸くなったもんだなっていう感慨を覚えた。

 エロゲのやり過ぎだ...もう、お互いいい歳なんだからさ。

カーマ来てんだけどさ、昨夜 TV 通販で 6 千ナンボで売ってたのと全く同じ大理石加工のフライパンが 1980 で置いてあったのでウンコ漏洩した。

 通販の奴は、「今ならもう 2 個」とか言ってなかったか?

なんか三ヶ月ぐらい点けっぱにしといたらパソ死んだ。とりあえずセーフモードで立ち上がる途中に電源ブツッてなってリセットかかるんでもう絶望的だと思う。
死ぬ前にデバイスマネージャ見た時は SCSI 死んでたっぽいんだけど、それが判ったところで今更。
級長ちんげ生えすぎだっつーの。

 脈絡のない最後の一行に悪意しか感じない私は何かがおかしいのでしょうか、それとも単なる被害妄想でしょうか?

今レジ立ってんだけどさ、肛奥でニホンオオカミ飼ってるかのような唸り声がずっと聞こえてくるのに店員俺しかいねえ状況だし、今夜セブンイレブン全店舗営業停止のニュースを楽しみにしてていいと思う。

 オマイの苗字は"日本の苗字 7000 傑"でも最低ランクなのだから、自重せよ。

結局三国志 10 の PK 付き 14000 円を買おうか買うまいか買おうか買うまいか買おうか買うまいかで閉店間際のエイデン柴田店で 40 分近く懊悩しまくった揚句の果てに買ったつもりになって帰って来て麻婆飯作って食った後にさーパパ三国志 10 最初っからパラメータ最強にしまくった新武将 128 人ぐらい作成しまくるぞーって思ってパソ部屋行ったら実際買ってない現実と向き合った時の寂寥感といったらなかった。心底自分にガッカリだ。

 "日清のラーメン屋さん" みたいだな。「行ったつもりで我が家で...」 ま、こっちは腹は膨れるのだがな。

日中ヒマだったんで一人で安宅家の人々ごっこしてみたんだけど、あまりにも人としてどうかと思ったのでこのネタ封印する事にした。

 何の事か解らなかったのでググったら、すげぇストーリーだな、オイ!

新しくうちに来た冷蔵庫、なんか勝手に氷作るわだだっ広いわで、野菜何買ってこようとか考えてたら便意に襲われた。

 夜中にガラガラッって音がするので (多分)、"かなり巨大なゴキブリが台所で這いずり回ってる" のだと妄想すると、夜も眠れなくなると思う。

よく級長が職場の会議でケツアナルって言うけどさ、ケツアナルって何か古代インカの太陽神って感じしねえ?

 "ケツァルコワトル" の事かー!って、ネタ元を説明しないと意味不明なネタって、ネタとしての存在意義を疑われても仕方がないと思う。

3800 万のマンション買う気になって検討してたら超ウンコしたくなったもんで、亜音速でベビーカー押して最寄りのバロー便所に駆け込んだ。

 そういや、お子様が生まれたのだったな...おめでとう。願わくば、この子が親父或いは叔父 (1) や叔父 (2) のようなヲタに育ちませんように。

今日のトリビア
コンビニに男性客が支払いに来るゲームチェックは
大半が出会い系関係である。

 人生イロイロ...男もイロイロ...さ。

ファミ通の表紙見たら SCE 池尻大作氏ってのが出てたんで、いつから世界のソニーはナンミョウの企業舎弟に成り下がったのかと早合点して愕然としたのだ!!!!!!!!!!!!!!!!!!!!!!!!!!!!@@;;;;;;;;;;

 "渡辺信一郎""ワタナベシンイチ" と "ナベシン" と "スパイク" と "ダンス☆マン" と "ダソヌ☆マソ" みたいなものか。ぶっちゃ毛、一見さんにはよくわからないけどね。


 BACK  古いのを読む
新しいのを読む