(09/09/01~)

09/09/02

第14回 エンバカデロ・デベロッパーキャンプ
 本日開催ですね。やっぱりコレですよね(何が?)。それはともかく筑木さん、がんばって。


09/09/05

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (序文)
 DocWiki が "あんな状態" で、RAD STUDIO 2010 のヘルプが (ゲフンゲフン) な状態なため、H2 ヘルプ から CHM を作ってみる事にしました。

 ご存知ない方も多いかもしれませんが、実は日本語版の CHM は存在しています。

 RAD Studio 2009 (Help Update 1 相当)

 RAD Studio 2007 (Help Update 4 相当)  「これらが何故公開してないのか?」という疑問は DL して開いてみれば氷解します...文字化けが発生しており、全文検索もうまくヒットしないのです。さらに言えば 2009 の CHM はトピックが大量に欠損しています。2007 には "ちゃんとした CHM" が存在しますが、残念ながら Update 1 相当です。

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (CHM の罠)
 CHM 形式のヘルプは HTML から作られますが、実は UTF-8 が使えません。日本語版 Windows だと、Shift-JIS でコンテンツを作る必要があります。<meta> タグの文字コード指定は効くのは効くのですが、インデックスや目次、検索等にはデフォルト ANSI コードページが使われます...これで文字化けしてしまうのです。

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (Rad Studio 2007 の CHM を作る)
 RAD Studio 2007 の CHM を作るのは比較的簡単です。

  1. 前述の CHM ファイルを DL
  2. HTML Help Workshop で逆コンパイル
  3. 得られた HTML の <meta> タグにある "utf-8" を "shift_jis" に変更し、ファイルを SHIFT-JIS で保存。
  4. *.hhk / *.hhc も <meta> タグにある "utf-8" を "shift_jis" に変更し、ファイルを SHIFT-JIS で保存。
  5. *.hhp / *.css を SHIFT-JIS で保存。
  6. HTML Help Workshop で再コンパイル
 これだけで、それなりに使えるヘルプができると思います。お好みで、*.hhc (コンテンツインデックス) や *.hhk (キーワードファイル) を編集するといいでしょう。

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (Rad Studio 2009 の CHM を作る)
 前述の CHM が使い物にならないので、H2 ヘルプを CHM に変換しなくてはなりません。

  1. HxS を H2 プロジェクト形式に逆コンパイル
  2. 得られた HTML の <meta> タグにある "utf-8" を "shift_jis" に変更し、ファイルを SHIFT-JIS で保存。
  3. *.hhk / *.hhc / *.hhp を自分で作る
  4. *.css を SHIFT-JIS で保存。
  5. HTML Help Workshop でプロジェクトを作ってコンパイル
 逆コンパイルには HxComp.exe を使うか、シェアウェアの FAR HTML を使います。但し、逆コンパイルしても CHM 用のプロジェクトは得られませんので、FAR HTML で変換するか、HTML Help Workshop で新規作成する必要があります。

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (Tips)
 使い物になるヘルプを作るにはちょっとした手間が必要です。

・RAD STUDIO の H2 ヘルプ (HxS) から CHM 形式のヘルプを作る (まとめ)
 こうして得られた CHM ヘルプですが、ヘルプビューワが ANSI デフォルトコードページに依存するという仕様のため、日本語版以外の Windows やロケールを変更していると正しく日本語で表示されない事になります。H2 ヘルプの優位性はそこにあるのですが、日本人が日本語環境でしか使わないのであれば、CHM 化したヘルプを使うのもアリでしょう。

 手元には、2007 / 2009 の CHM ファイル群がありますが、諸事情により公開する事ができません。「CHM がどうしても欲しい」という方がいらっしゃいましたら、公式フォーラム に意見を頂ければ幸いです。


09/09/16

・RAD Studio 2010 スタッフ

Unicode SynEdit
 2009/09/14 に更新されていた。Unicode 版 SynEdit で、IBConsole のエディタ部にも使われている。SynHighlighterJava.pas に 0x80 以降の ANSI 文字が使われているのは直っておらず、DH山本さんの記事 を参考に修正するしかないと思われる。SynEdit.inc は変更になっているので、Delphi 2010 にインストールする事が可能だ。

 サロゲートペアが含まれるとキャレットの移動がおかしいが、それ以外では普通に使えるエディタコンポーネントだ...矩形選択なんかも普通にできる。


09/09/18

MECSUtils 1.30
 リリース。山本隆さんのブログの "Windows 2000でWideCharToMultiByte関数を使うと、ISO-2022-JPのバイト数を間違う" の件です(フォーラムにも同様の投稿があります)。それと、"全角チルダ / 波ダッシュ問題" をどうにかするための MecsMappingFixJA() を追加してあります。


09/09/25

MECSUtils 1.35
 リリース。この件では、山本隆さんに大変お世話になった。この場をお借りしてお礼を申し上げたい。

 さてさて。一体どういう事かと言うと、よくある "全角チルダ/波ダッシュ問題" なのだが、類似する問題を洗い出していたらイロイロとマズい点があったという事。

 "全角チルダ/波ダッシュ問題" は、"どの環境でファイルが作られたか?" によって状況が異なる。JIS X 0208 <-> Unicode へのマッピングが双方向に 1:多 であったり、多:1 だったりするので、環境によってマッピングされる文字が異なるという現象が起きる事となる。同じ文字集合を利用している Shift-JIS / JIS-Code / EUC-JP なのだが、Windows の Shift-JIS (CP932) は、他の文字コードとは違うマッピングの挙動を示す。

 ぶっちゃけ Windows だの Unix だの Linux だの Mac だのでおのおの JIS X 0208 <-> Unicode のマッピング方法が異なるという事だ。

 よって、Unicode から Shift-JIS へエクスポートする場合には、MecsMappingFix_UnicodeToCP932() を使うべきなのか、MecsMappingFix_UnicodeToJISX0208() を使うべきなのかは 環境に依存する という事になる。逆説的に言えば、Unicode -> Ansi 変換ルーチンに前もって "全角チルダ/波ダッシュ問題" の対処法を組み込んでしまうのは危険だという事になる。

・MacOSX との非互換
 MECSUtils に MacOSX 用のマッピング関数を作ろうと思ったがやめている...根本的な解決方法がないように思えたからだ。

 MacOSX で作成された Unicode のテキストファイルを Windows に持ってくると、\記号 (U+005C: REVERSE SOLIDUS) が ¥記号 (U+00A5: YEN SIGN) になっている。Windows で Shift-JIS の \記号 (0x5C) を Unicode に変換すると U+005C になる。このテキストファイルを MacOSX に持っていって Shift-JIS に変換すると、U+005C は、0x80 になってしまう...つまり、Windows のソースコードを Unicode で保存し、MacOSX でShift-JIS に変換すると "パスデリミタ全滅" という事になる。

 また、MacOSX の Shift-JIS には、© (0xFD)、™ (0xFE) なんて文字があるが、Windows の CP932 にはそんな文字はないため、MacOSX で作られた Shift-JIS ファイルを Windows で Unicode に変換しようとしても正しく変換できない。加えて言えば、Unicode で © (U+00A9)、™ (U+2122) を記述したファイルを Windows で Shift-JIS に変換して MacOSX に持って行っても、当然ながら © (0xFD)、™ (0xFE) にはならない。

 さて前置きが長くなったが、この問題を解決するには、"MacOSX の Shift-JIS を Windows 上で Unicode と相互変換できればいい" という事が解る。

// Delphi 2009 / 2010 での例
var
  SL: TStringList;
  Enc: TEncoding;
begin
  SL := TstringList.Create;
  Enc := TEncoding.GetEncoding(10001); // x-mac-japanese (Mac Shift-JIS)
  try
    SL.LoadFromFile('C:\x-mac-japanese.txt', Enc);
    ShowMessage(SL.Text);
  finally
    Enc.Free;
    SL.Free;
  end;
end;

// Delphi 2009 / 2010 での例
var
  SL: TStringList;
  Enc: TEncoding;
begin
  SL := TstringList.Create;
  Enc := TEncoding.GetEncoding(10001); // x-mac-japanese (Mac Shift-JIS)
  try
    SL.Text := #$00A9#$2122;
    SL.SaveToFile('C:\x-mac-japanese.txt', Enc);
  finally
    Enc.Free;
    SL.Free;
  end;
end;

 上記コードのように、コードページ 10001 (x-mac-japanese) を使えばこの問題は回避できる (でも、MacOSX の Jis-Code とかはどうなっているのだろうね?)。

 Windows で作られた Unicode ファイル を MacOSX に持っていく時には、MecsMappingFix_UnicodeToJISX0208() をやった上で \記号 (U+005C: REVERSE SOLIDUS) を ¥記号 (U+00A5: YEN SIGN) に置換したものを用意すると親切なのかもしれない。こうしてできた Unicode ファイルは MacOSX 上で Shift-JIS に変換しても文字化けを起こさない。

 MECSUtils で MacOSX 用の関数を用意しなかったのは、\記号 (U+005C: REVERSE SOLIDUS) を ¥記号 (U+00A5: YEN SIGN) に置換すべき時とそうでない時の区別がつかないからだ (パスデリミタを表したいのか、円記号を表したいのか判断できない)。

 Windows で作られた Unicode ファイル を MacOSX で Unicode のまま利用する分には殆ど問題は起きないと思われる (逆もしかり)。Windows であらかじめ x-mac-japanese な Shift-JIS ファイルを用意するのであれば、やはり MECSUtils には、再マッピング関数不要...という事になる。"MacOSX 上で Shift-JIS に変換される事を前提で Unicode ファイルを渡す" 事なんて滅多にないだろうし。


09/09/27

MECSUtils
 1.30~1.36 での変更点を書いていなかったのでちょっと追記。

v1.30
・MecsMappingFix_JA() を追加
・Windows 2000 でも WideCharToMultibyte が正常動作するようにした (UTF16ToAnsi)。

v1.31
・誤ってテスト用ユニットをアップしてしまっていたので、バージョン番号だけを上げて再アップ。

v1.32
・バグFix

v1.33
・MecsMappingFix_JISX0208ToUnicode() を追加
・MecsMappingFix_UnicodeToJISX0208() を追加
・パフォーマンスを向上させた。

v1.34
・U+2014: HORIZONTAL BAR / U+2015: EM DASH の処理を追加
・U+203E: OVERLINE / U+FFE3: FULLWIDTH MACRON の処理を追加

v1.35
・CP932 (Shift-JIS) でも一部変換ミスが起こるため、
  - MecsMappingFix_CP932ToUnicode()
  - MecsMappingFix_UnicodeToCP932()
 を追加。

v1.36
・Windows 2000 における UTF16ToAnsi() を
  - iso-2022-kr (CP20225)
  - iso-2022-cn (CP20227)
  - iso-2022-tw (CP20229)
 でも正常動作するように修正。

 Windows 2000 で WideCharToMultibyte がバッファ容量計算をミスしてしまう件は、MECSUtils だと UTF16ToAnsi() がこの影響を受ける。山本隆さんより

(前略)
必要なバッファサイズ = 文字数 * (先頭のエスケープシーケンスの3バイト + 文字の2バイト)
                       + 末尾のエスケープシーケンス + 終端の\0

となり、

BufSize := (Length(WText) * 5 + 4);

で求められると思いますが、いかがでしょうか。

 という意見を頂いていた。元々この部分は、

BufSize := Length(WText) * 3;

 と漠然とした計算をしていたのだけれど、突き詰めて考えてみると、

W := 'あ';
L := Length(W); // L=1
<s>あ<e>
3 + 2 + 3 (+ 1) = 9
Ratio: 9

ワーストケースは全角文字(ANSI 2byte文字)×1 の場合です。
次に非効率なのは、全角文字…半角文字…全角文字…の繰り返しで、最後が全角文字で終わる場合です。
(省略)
半角文字数 を n とすると
ratio := ((n + 1) * 9) / (n * 2 + 1);
となります。

文字数=3  n=1  Ratio=6.0 必要なバイト数=18 確保されるバイト数=19
文字数=5  n=2  Ratio=5.4 必要なバイト数=27 確保されるバイト数=29
文字数=7  n=3  Ratio=5.1 必要なバイト数=36 確保されるバイト数=39
文字数=9  n=4  Ratio=5.0 必要なバイト数=45 確保されるバイト数=49
文字数=11 n=5  Ratio=4.9 必要なバイト数=54 確保されるバイト数=59
文字数=13 n=6  Ratio=4.8 必要なバイト数=63 確保されるバイト数=69
文字数=15 n=7  Ratio=4.8 必要なバイト数=72 確保されるバイト数=79
文字数=17 n=8  Ratio=4.8 必要なバイト数=81 確保されるバイト数=89
文字数=19 n=9  Ratio=4.7 必要なバイト数=90 確保されるバイト数=99
文字数=21 n=10 Ratio=4.7 必要なバイト数=99 確保されるバイト数=109
(最終的に Ratio=4.5 へ収束)

BufSize := (Length(WText) * 5 + 4);
よって、この計算で間違いないです。

文字数 2 以下は、

半角:      文字数=1 Ratio=2.0 必要なバイト数=2  確保されるバイト数=9
全角:      文字数=1 Ratio=9.0 必要なバイト数=9  確保されるバイト数=9
半角+半角: 文字数=2 Ratio=1.5 必要なバイト数=3  確保されるバイト数=14
半角+全角: 文字数=2 Ratio=5.0 必要なバイト数=10 確保されるバイト数=14
全角+半角: 文字数=2 Ratio=5.0 必要なバイト数=10 確保されるバイト数=14
全角+全角: 文字数=2 Ratio=5.5 必要なバイト数=11 確保されるバイト数=14

なので問題ありません。

 こういう事になる。

 ただしこのままだと文字列が長くなるにつれ、ワーストケースで確保しなくてはならないバッファ量よりもさらに 1割程度多くバッファを確保してしまう。文字数が3文字を超えた場合のワーストケースは、 "全角文字…半角文字…全角文字…の繰り返しで、最後が全角文字で終わる場合" なのだが、

BufSize := (Length(WText) * 5) + 4 - (半角文字の数);

 が、ワーストケースに於ける "最適なバッファ確保量" となるため、

BufSize := (Length(WText) * 5) + 4 - (Length(WText) div 2);

 現在ではこのようなロジックで落ち着いている。文字数が3文字を超えた場合のワーストケースは "文字列が全角半角の繰り返しで文字数は奇数となる" ため、単純に文字数を 2 で割ってやれば半角文字の数を導き出す事ができる。

BufSize := (全角文字の数 * 5) + 4;

 本当はこうなのだけれども、厳密に全角文字の数を算出するには一旦 AnsiString への変換等が発生するため、本末転倒な事になってしまう。EAW で調べるのはちょっと危険そうだし。

・念のために...
 Windows 2000 に於けるバッファの計算ミスの件は QC を入れておいた。

 TEncoding とかがモロに影響を受けるので、「Windows のバグではあるけれど、RTL側で修正を入れるべきだ」と思われる方は是非 Vote を。日本人以外はあまり Vote してくれないと思うので、一応。


09/09/29

・ISO-2022 系のバッファサイズ計算
 ISO-2022-CN はエスケープシーケンスが4バイトで全角->全角でもエスケープする事があるってか (資料)。うーん、WideString のサイズからバッファサイズを求めようとすると、

BufSize := (Length(WText) * 6) + 4;

 程度は必要な気がするなぁ...。ま、現実的に使われている ISO-2022 は ISO-2022-JP 及びその亜種だけ (多分) だからどうでもいいって言えばどうでもいいけどね。

・CP50220 / CP50221 / CP50222 の違い
 以下の表のようになる

CodePage エスケープ 半角カナ
50220 全角文字や半角文字に変化した場合に3バイトのエスケープが発生する 全角文字に変換される (半角カナは存在しない)
50221 全角文字や半角文字、半角カナに変化した場合に3バイトのエスケープが発生する
エスケープシーケンスでエスケープされる
50222 全角文字や半角文字に変化した場合に3バイトのエスケープが発生する <SI>/<SO> でエスケープされる

 最後の文字が ASCII 以外の文字の場合には ASCII へのエスケープが末尾に必要となる。


09/09/30

Delphi の Tips
 ちょっと増えました。

 リソース絡みが 3 つです。


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