(08/05/01 ~)

08/05/14

全角と半角
  SHIFT-JIS では基本的には 2 バイト文字は全角と考えて差し支えありませんでした (例外的に 2 バイト半角カナがあります)。ですが、Unicode には全角 / 半角という概念がありません。

 例えばギリシャ文字。ギリシャ文字は ANSI コードページによっては 1 バイト文字です。日本語文字エンコードに於いては 2 バイト文字です。では、ギリシャ文字を Unicode で表現する場合は半角なのでしょうか、それとも全角なのでしょうか?

 答えは "不明"。全角でも半角でもありません。

 半角/全角というのは、文字コードとは関係なく "表示上の概念" であり、アルファベット圏ではギリシャ文字は半角の大きさで見え、日本では全角の大きさで見えます。文字コードとフォントには何の因果関係もないという訳です。いかな Unicode であっても、実際に表示される文字 (フォント) の幅はロケールに依存する事となります。

 固定幅で文字を描画する事を考えてみましょう。これまでは、1 バイト文字 / 2 バイト文字を判断して幅を調整すれば簡単に描画できました。では Unicode の場合にはどうしたらいいのでしょう?

"Unicode という文字コード" だけではこの問題は解決しません。この問題を解決するには、 Unicode コンソシアムで策定されている EastAsianWidth 属性を利用します。詳しくは Wikipedia の "東アジアの文字幅" を参考にして下さい。

 固定幅で文字を描画するなら、 EastAsianWidth は...

 文字にこのような影響を与える事になります。文字幅取得の具体的な実装は "MBCSUtils" にあります (Delphi コードです) ので、興味のある方はご覧ください。要は Unicode に於いてはバイトサイズと全角 / 半角の概念はキッパリと忘れて、EastAsianWidthロケールを意識する必要がある、という事です。


08/05/20

全角と半角
 昔話です。昔々はテキストを表示するのに VRAM を使っていました。 VRAM と言うのはビデオメモリの事ですが、現在のビットマップなビデオメモリではなく、テキスト VRAM というものの事です。テキスト VRAM はそのアドレスに値を書き込むと画面に文字が表示されました。

H e l l o , w o r l d .                                                                                                                                        
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 こんな感じです。テキスト VRAM の先頭に 0x48 を書き込むと "H" が表示される訳です。これが単色のテキスト VRAM で、色の出せるテキスト VRAM の場合には RGB のテキスト VRAM が 3 プレーン用意されていて、それぞれのプレーンに同じ文字を書き込んで色を表現するものや、 1 文字分を 2 バイトで表現し、半分をアトリビュートエリアに使うものがありました。テキスト VRAM は固定されたサイズですから、フォントも ANK 文字で 16x8 、漢字で 16x16 と固定されていました。大きな文字やプロポーショナルな文字をテキスト VRAM に書く事はできず、グラフィック VRAM と呼ばれるビットマップなメモリに書く必要がありました。余談ですが、グラフィック VRAM にも水平ビットマップ/垂直ビットマップ等の種類がありました。

 昔々は "文字=メモリ" で、"文字幅=バイトサイズ" だった訳ですね。スクロールや文字列コピーはメモリを操作する事で実現しました。フォントは ROM として用意されていたので、テキスト VRAM で表示されるフォントを変更する方法は基本的にありません。表示位置を 1 ドットずらす事も基本的には不可能でした。テキスト VRAM に書き込む文字コードも PC-98 では JIS-CODE 固定でした (PC-98 用の MS-DOS は SHIFT-JIS ですが、テキスト VRAM 自体は JIS-CODE です)。

 長々と書きましたが、要はこれが "全角と半角の意味" でして。現在の Windows 等では全角 / 半角と文字エンコード、バイトサイズ、文字の大きさ (幅) には因果関係はないので、特に Unicode を扱う場合には注意が必要です。


08/05/22

青ミミズ
 <!>グロ注意。ミミズが苦手なヒトは絶対にリンクを踏まないように!<!>

 プロフィールでも書いていますが、私は "青ミミズ" がキライです。今日まで、このミミズの正式名称を知りませんでしたが、"シーボルトミミズ (カンタロウ)" と言うそうです。山の中にカブトムシやクワガタを捕りに行くと遭遇するんですよねぇ...。"青ミミズ" と言っていましたが、正確な色はこちらが近いです。濃い青で、表面が虹色なんですよ。心の準備が出来ていれば、「キレイだなぁ...」 で済むのですが、コイツとはいきなり遭遇する事 (草むらを掻き分けたら目の前に居る、とか) が多いので、ショックがデカいんです。30cm を超えるのはザラなくせして、意外と機敏に暴れるんですよ...コイツ。

 "青ミミズ" の話をしても不思議がられる (話が通じない) 事が多いのは、分布が西日本なのと、山中以外ではお目に掛かる事が少ないからでしょうね。


08/05/26

AVG Anti-Virus Free Edition
 7.5 をインストールしている方は 8.0 へのアップデートを催促するポップアップを見た事がある事でしょう。素直にアップデートしようとすると、有償版の AVG 8.0 へアップデートされてしまいます。ちゃんと 8.0 の FreeEdition がありますので、 7.5 をアンインストールしてから 8.0 (Free Edition) をインストールして下さい。

 こんな当たり前の事を何故書くのかと言いますと、有償版の AVG 8.0 へアップデートした場合、最悪の場合

インターネット接続が不能になる

 からです。この症状になった場合、デバイスマネージャに AVG の "ミニポートドライバ" がエクスクラメーションマーク付きで存在するハズです。このミニポートドライバはアンインストーラでも削除されず、デバイスマネージャからも削除できません (セーフモードでも)。詳細には検証できていませんが、検体を一つ Get したので、調べてみたいと思います。

 

...まぁ、その症状になったらインターネットに接続できない訳で、この情報も見れないのですが。できるだけ "インターネットに接続せずに解決する方法" を模索してみます。同様の症状の方が居らしたら...または今後、同様の症状に悩む方がいらっしゃるかもしれませんが、気長に続報をお待ち下さい。

AVG Installer
 こんなのも作ってあります


08/05/27

AVG Anti-Virus Free Edition
  "検体" を調べてみた。ナルホド...確かに "AVG miniport Driver" はデバイスマネージャから消えない。試行錯誤の末、以下の手順で削除する事が出来た。

  1. 現在インストールされている AVG をアンインストールする。
  2. "AVG Internet Security" の 30 日トライアルバージョンを DL する。
  3. デフォルトオプションのままインストールする。
  4. アンインストールせずにインストーラを再度実行。
  5. カスタムセットアップに入り、チェックボックスをすべて外してインストール。
  6. アンインストール。
 上記手順の中で何度か再起動があると思う。結局 "インターネットに接続せずに解決する方法" を探しだせなかったな...。


08/05/28

WMS Idle
 WindowsXP の終了時に WMS Idle のエラーが出る場合には nero を疑ってみましょう。終了時、やたらと時間が掛かる場合も同様です。これを回避するには nero のアップデートを行えばいいようです。


08/05/29

IBConsole 日本語版+α
  Windows 版(rel.53)をリリース。テンプレート機能を強化。例えば以下のようなテーブルがあったとすると、

/* Table: TEST, Owner: SYSDBA */

CREATE TABLE "TEST" 
(
  "FIELD_01"    INT64 NOT NULL,
  "FIELD_02"    BLOB SUB_TYPE -1 SEGMENT SIZE 80,
  "FIELD_03"    BLOB SUB_TYPE 0 SEGMENT SIZE 80,
  "FIELD_04"    BLOB SUB_TYPE TEXT SEGMENT SIZE 80,
  "FIELD_05"    BLOB SUB_TYPE BLR SEGMENT SIZE 80,
  "FIELD_06"    BLOB SUB_TYPE ACL SEGMENT SIZE 80,
  "FIELD_07"    BLOB SUB_TYPE RANGES SEGMENT SIZE 80,
  "FIELD_08"    BLOB SUB_TYPE SUMMARY SEGMENT SIZE 80,
  "FIELD_09"    BLOB SUB_TYPE FORMAT SEGMENT SIZE 80,
  "FIELD_10"    CHAR(10),
  "FIELD_11"    DATE,
  "FIELD_12"    DECIMAL(21),
  "FIELD_13"    DECIMAL(83),
  "FIELD_14"    DECIMAL(1818),
  "FIELD_15"    DOUBLE PRECISION,
  "FIELD_16"    FLOAT,
  "FIELD_17"    INTEGER,
  "FIELD_18"    NUMERIC(21),
  "FIELD_19"    NUMERIC(83),
  "FIELD_20"    NUMERIC(1818),
  "FIELD_21"    SMALLINT,
  "FIELD_22"    TIME,
  "FIELD_23"    TIMESTAMP,
  "FIELD_24"    VARCHAR(10),
 PRIMARY KEY ("FIELD_01")
);

 〔パラメータ (P)〕ボタンを押下すると、

{ Table: TEST, Delphi Parameters }

  // FieldByName
  FieldByName('FIELD_01').AsVariant  := ;
  FieldByName('FIELD_02').AsVariant  := ;
  FieldByName('FIELD_03').AsVariant  := ;
  FieldByName('FIELD_04').AsString   := ;
  FieldByName('FIELD_05').AsVariant  := ;
  FieldByName('FIELD_06').AsVariant  := ;
  FieldByName('FIELD_07').AsVariant  := ;
  FieldByName('FIELD_08').AsVariant  := ;
  FieldByName('FIELD_09').AsVariant  := ;
  FieldByName('FIELD_10').AsString   := ;
  FieldByName('FIELD_11').AsDateTime := ;
  FieldByName('FIELD_12').AsBCD      := ;
  FieldByName('FIELD_13').AsBCD      := ;
  FieldByName('FIELD_14').AsBCD      := ;
  FieldByName('FIELD_15').AsCurrency := ;
  FieldByName('FIELD_16').AsCurrency := ;
  FieldByName('FIELD_17').AsInteger  := ;
  FieldByName('FIELD_18').AsBCD      := ;
  FieldByName('FIELD_19').AsBCD      := ;
  FieldByName('FIELD_20').AsBCD      := ;
  FieldByName('FIELD_21').AsInteger  := ;
  FieldByName('FIELD_22').AsDateTime := ;
  FieldByName('FIELD_23').AsDateTime := ;
  FieldByName('FIELD_24').AsString   := ;

  // ParamByName
  ParamByName('FIELD_01').AsVariant  := ;
  ParamByName('FIELD_02').AsVariant  := ;
  ParamByName('FIELD_03').AsVariant  := ;
  ParamByName('FIELD_04').AsString   := ;
  ParamByName('FIELD_05').AsVariant  := ;
  ParamByName('FIELD_06').AsVariant  := ;
  ParamByName('FIELD_07').AsVariant  := ;
  ParamByName('FIELD_08').AsVariant  := ;
  ParamByName('FIELD_09').AsVariant  := ;
  ParamByName('FIELD_10').AsString   := ;
  ParamByName('FIELD_11').AsDateTime := ;
  ParamByName('FIELD_12').AsBCD      := ;
  ParamByName('FIELD_13').AsBCD      := ;
  ParamByName('FIELD_14').AsBCD      := ;
  ParamByName('FIELD_15').AsCurrency := ;
  ParamByName('FIELD_16').AsCurrency := ;
  ParamByName('FIELD_17').AsInteger  := ;
  ParamByName('FIELD_18').AsBCD      := ;
  ParamByName('FIELD_19').AsBCD      := ;
  ParamByName('FIELD_20').AsBCD      := ;
  ParamByName('FIELD_21').AsInteger  := ;
  ParamByName('FIELD_22').AsDateTime := ;
  ParamByName('FIELD_23').AsDateTime := ;
  ParamByName('FIELD_24').AsString   := ;

 このようなコードを吐きます。[言語] で "C++" を選択すると、

/* Table: TEST, C++ Parameters */

  // FieldByName
  FieldByName("FIELD_01")->AsVariant  = ;
  FieldByName("FIELD_02")->AsVariant  = ;
  FieldByName("FIELD_03")->AsVariant  = ;
  FieldByName("FIELD_04")->AsString   = ;
  FieldByName("FIELD_05")->AsVariant  = ;
  FieldByName("FIELD_06")->AsVariant  = ;
  FieldByName("FIELD_07")->AsVariant  = ;
  FieldByName("FIELD_08")->AsVariant  = ;
  FieldByName("FIELD_09")->AsVariant  = ;
  FieldByName("FIELD_10")->AsString   = ;
  FieldByName("FIELD_11")->AsDateTime = ;
  FieldByName("FIELD_12")->AsBCD      = ;
  FieldByName("FIELD_13")->AsBCD      = ;
  FieldByName("FIELD_14")->AsBCD      = ;
  FieldByName("FIELD_15")->AsCurrency = ;
  FieldByName("FIELD_16")->AsCurrency = ;
  FieldByName("FIELD_17")->AsInteger  = ;
  FieldByName("FIELD_18")->AsBCD      = ;
  FieldByName("FIELD_19")->AsBCD      = ;
  FieldByName("FIELD_20")->AsBCD      = ;
  FieldByName("FIELD_21")->AsInteger  = ;
  FieldByName("FIELD_22")->AsDateTime = ;
  FieldByName("FIELD_23")->AsDateTime = ;
  FieldByName("FIELD_24")->AsString   = ;

  // ParamByName
  ParamByName("FIELD_01")->AsVariant  = ;
  ParamByName("FIELD_02")->AsVariant  = ;
  ParamByName("FIELD_03")->AsVariant  = ;
  ParamByName("FIELD_04")->AsString   = ;
  ParamByName("FIELD_05")->AsVariant  = ;
  ParamByName("FIELD_06")->AsVariant  = ;
  ParamByName("FIELD_07")->AsVariant  = ;
  ParamByName("FIELD_08")->AsVariant  = ;
  ParamByName("FIELD_09")->AsVariant  = ;
  ParamByName("FIELD_10")->AsString   = ;
  ParamByName("FIELD_11")->AsDateTime = ;
  ParamByName("FIELD_12")->AsBCD      = ;
  ParamByName("FIELD_13")->AsBCD      = ;
  ParamByName("FIELD_14")->AsBCD      = ;
  ParamByName("FIELD_15")->AsCurrency = ;
  ParamByName("FIELD_16")->AsCurrency = ;
  ParamByName("FIELD_17")->AsInteger  = ;
  ParamByName("FIELD_18")->AsBCD      = ;
  ParamByName("FIELD_19")->AsBCD      = ;
  ParamByName("FIELD_20")->AsBCD      = ;
  ParamByName("FIELD_21")->AsInteger  = ;
  ParamByName("FIELD_22")->AsDateTime = ;
  ParamByName("FIELD_23")->AsDateTime = ;
  ParamByName("FIELD_24")->AsString   = ;

 こうなります。さらに、〔選択クエリ (S)〕/〔挿入クエリ (I)〕/〔更新クエリ (U)〕/〔削除クエリ (D)〕を押してみると...

/* Table: TEST, Select Query */

SELECT
  FIELD_01,
  FIELD_02,
  FIELD_03,
  FIELD_04,
  FIELD_05,
  FIELD_06,
  FIELD_07,
  FIELD_08,
  FIELD_09,
  FIELD_10,
  FIELD_11,
  FIELD_12,
  FIELD_13,
  FIELD_14,
  FIELD_15,
  FIELD_16,
  FIELD_17,
  FIELD_18,
  FIELD_19,
  FIELD_20,
  FIELD_21,
  FIELD_22,
  FIELD_23,
  FIELD_24
FROM
  TEST
WHERE
  (FIELD_01 = :_FIELD_01)
ORDER BY
  FIELD_01;

/*
  ParamByName('_FIELD_01').AsVariant  := ;
*/

/* Table: TEST, Insert Query */

INSERT INTO TEST
(
  FIELD_01,
  FIELD_02,
  FIELD_03,
  FIELD_04,
  FIELD_05,
  FIELD_06,
  FIELD_07,
  FIELD_08,
  FIELD_09,
  FIELD_10,
  FIELD_11,
  FIELD_12,
  FIELD_13,
  FIELD_14,
  FIELD_15,
  FIELD_16,
  FIELD_17,
  FIELD_18,
  FIELD_19,
  FIELD_20,
  FIELD_21,
  FIELD_22,
  FIELD_23,
  FIELD_24
)
VALUES
(
  :FIELD_01,
  :FIELD_02,
  :FIELD_03,
  :FIELD_04,
  :FIELD_05,
  :FIELD_06,
  :FIELD_07,
  :FIELD_08,
  :FIELD_09,
  :FIELD_10,
  :FIELD_11,
  :FIELD_12,
  :FIELD_13,
  :FIELD_14,
  :FIELD_15,
  :FIELD_16,
  :FIELD_17,
  :FIELD_18,
  :FIELD_19,
  :FIELD_20,
  :FIELD_21,
  :FIELD_22,
  :FIELD_23,
  :FIELD_24
);

/*
  ParamByName('FIELD_01').AsVariant  := ;
  ParamByName('FIELD_02').AsVariant  := ;
  ParamByName('FIELD_03').AsVariant  := ;
  ParamByName('FIELD_04').AsString   := ;
  ParamByName('FIELD_05').AsVariant  := ;
  ParamByName('FIELD_06').AsVariant  := ;
  ParamByName('FIELD_07').AsVariant  := ;
  ParamByName('FIELD_08').AsVariant  := ;
  ParamByName('FIELD_09').AsVariant  := ;
  ParamByName('FIELD_10').AsString   := ;
  ParamByName('FIELD_11').AsDateTime := ;
  ParamByName('FIELD_12').AsBCD      := ;
  ParamByName('FIELD_13').AsBCD      := ;
  ParamByName('FIELD_14').AsBCD      := ;
  ParamByName('FIELD_15').AsCurrency := ;
  ParamByName('FIELD_16').AsCurrency := ;
  ParamByName('FIELD_17').AsInteger  := ;
  ParamByName('FIELD_18').AsBCD      := ;
  ParamByName('FIELD_19').AsBCD      := ;
  ParamByName('FIELD_20').AsBCD      := ;
  ParamByName('FIELD_21').AsInteger  := ;
  ParamByName('FIELD_22').AsDateTime := ;
  ParamByName('FIELD_23').AsDateTime := ;
  ParamByName('FIELD_24').AsString   := ;
*/

/* Table: TEST, Update Query */

UPDATE TEST
SET
  FIELD_02 = :FIELD_02,
  FIELD_03 = :FIELD_03,
  FIELD_04 = :FIELD_04,
  FIELD_05 = :FIELD_05,
  FIELD_06 = :FIELD_06,
  FIELD_07 = :FIELD_07,
  FIELD_08 = :FIELD_08,
  FIELD_09 = :FIELD_09,
  FIELD_10 = :FIELD_10,
  FIELD_11 = :FIELD_11,
  FIELD_12 = :FIELD_12,
  FIELD_13 = :FIELD_13,
  FIELD_14 = :FIELD_14,
  FIELD_15 = :FIELD_15,
  FIELD_16 = :FIELD_16,
  FIELD_17 = :FIELD_17,
  FIELD_18 = :FIELD_18,
  FIELD_19 = :FIELD_19,
  FIELD_20 = :FIELD_20,
  FIELD_21 = :FIELD_21,
  FIELD_22 = :FIELD_22,
  FIELD_23 = :FIELD_23,
  FIELD_24 = :FIELD_24
WHERE
  (FIELD_01 = :_FIELD_01);

/*
  ParamByName('FIELD_02' ).AsVariant  := ;
  ParamByName('FIELD_03' ).AsVariant  := ;
  ParamByName('FIELD_04' ).AsString   := ;
  ParamByName('FIELD_05' ).AsVariant  := ;
  ParamByName('FIELD_06' ).AsVariant  := ;
  ParamByName('FIELD_07' ).AsVariant  := ;
  ParamByName('FIELD_08' ).AsVariant  := ;
  ParamByName('FIELD_09' ).AsVariant  := ;
  ParamByName('FIELD_10' ).AsString   := ;
  ParamByName('FIELD_11' ).AsDateTime := ;
  ParamByName('FIELD_12' ).AsBCD      := ;
  ParamByName('FIELD_13' ).AsBCD      := ;
  ParamByName('FIELD_14' ).AsBCD      := ;
  ParamByName('FIELD_15' ).AsCurrency := ;
  ParamByName('FIELD_16' ).AsCurrency := ;
  ParamByName('FIELD_17' ).AsInteger  := ;
  ParamByName('FIELD_18' ).AsBCD      := ;
  ParamByName('FIELD_19' ).AsBCD      := ;
  ParamByName('FIELD_20' ).AsBCD      := ;
  ParamByName('FIELD_21' ).AsInteger  := ;
  ParamByName('FIELD_22' ).AsDateTime := ;
  ParamByName('FIELD_23' ).AsDateTime := ;
  ParamByName('FIELD_24' ).AsString   := ;

  ParamByName('_FIELD_01').AsVariant  := ;
*/

/* Table: TEST, Delete Query */

DELETE FROM TEST
WHERE
  (FIELD_01 = :_FIELD_01);

/*
  ParamByName('_FIELD_01').AsVariant  := ;
*/

 このように、パラメータに対応するソースコードをコメントで吐き出します (上記は言語が Delphi の場合)。 Linux 版は後程。

IBConsole 日本語版+α
 Linux 版 (rel.50) をリリース。変更箇所は Windows 版と同じです。

IBConsole 日本語版+α
 現在、"Delphi" と "C++Builder" があります。この機能は IBX 用のコードを吐きます。 IBX が用意されているのは、

 だけです。ソースコードを吐く [言語] として "Delphi for PHP" を追加しようと思ったのですが、基本 C++Builder 用のコードで流用できる (できない場合ってあるんでしょうか?) ので、やめました。

IBConsole 日本語版+α
 〔パラメータ (P)〕ボタンで吐かれる FieldByName の代入演算子の位置を変更。FieldByName に対して代入する事はまずない (言い切っちゃいます) ので、FieldByName は右辺にしました。 Windows 版 / Linux 版とも同名でアップロードしてあります。


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