PDIC/Unicode辞書形式仕様書

第0.90版

2007.7.24

SGM00353@niftyserve.or.jp TaN

1. はじめに

 この仕様書はPersonal Dictionary(略してPDIC) という英和辞書検索アプリケーションで使用している辞書の構造を述べています。 PDICは2008年現在、DOS,Windows(3.1, 95, 98, Me, NT4.0, 2000, XP,Vista),WindowsCE(PocketPC)上で動作しています。

 この辞書の特徴は単一キーで、検索が高速であるところです。登録データはブロックごとに分割した領域に格納することにより、インデックス部を最低限に抑え、コンパクトな辞書となっています。

この仕様書はプログラマ向けのもので、一般ユーザが読むべきものではありません。また、プログラミングに長けている人でもこの仕様書は難解です。というのは、この仕様書をメモ代わりに使用しているため、読者が理解しやすいように、というより、備忘録としているためです。

2. 辞書構造概略

2.1. 辞書の種類

PDICには現在公開されているもので次の種類があります。

辞書バージョン

一般名称

対応アプリケーション

1.00

旧辞書形式

DOS版PDIC Ver.3.xx~Ver.4.xx

2.00

新辞書形式1

DOS版PDIC Ver.5.xx以降及びPDIC for Windows(16bit版,32bit版)

3.00

新辞書形式2

PDIC for Windows (32bit版)

4.00

Hyper辞書形式

PDIC for Win32 Ver.3.xx以降

5.00

Hyper辞書形式

PDIC for Win32 Ver.5.00以降 (現在read/writeのみ、新規作成はできない)

5.00

Unicode辞書

PDIC/Unicode(初期)

6.00

Unicode辞書

PDIC/Unicode (~Ver.0.70)

6.10

Unicode辞書

PDIC/Unicode (Ver.0.80~)

2.2. 各辞書形式の内容

辞書形式

辞書サイズ

最大見出語長

最大訳語長

最大用例長

最大発音記号長

旧辞書形式
1.00
OLDDIC
スモール辞書
ミディアム辞書
ラージ辞書

忘れた

忘れた

忘れた

新辞書形式1
2.00
NEWDIC
タイニィ辞書
スモール辞書
ミディアム辞書
ラージ辞書

128バイト

300バイト

300バイト

新辞書形式2
3.00
NEWDIC2
タイニィ辞書
スモール辞書
ミディアム辞書
ラージ辞書

248バイト

3000バイト

20,000バイト (圧縮対応)

1,000バイト

ファイルリンクオブジェクト
OLEオブジェクト
圧縮対応
Hyper辞書形式
4.00
NEWDIC3

辞書サイズの区別はない

248バイト

3000バイト

20,000バイト (圧縮対応)

1,000バイト

ファイルリンクオブジェクト
OLEオブジェクト
圧縮対応
Hyper辞書形式
5.00
NEWDIC4

辞書サイズの区別はない

248バイト

3000バイト

20,000バイト (圧縮対応)

1,000バイト

ファイルリンクオブジェクト
OLEオブジェクト
圧縮対応
(辞書順辞書対応)
Unicode辞書
5.00
NEWDIC4

辞書サイズの区別はない

248バイト

3000バイト

20,000バイト (圧縮対応)

1,000バイト

ファイルリンクオブジェクト
OLEオブジェクト
圧縮対応
(辞書順辞書対応)
Unicode辞書2
6.00
NEWDIC5

辞書サイズの区別はない

248バイト

10000バイト

100,000バイト

(圧縮対応)

1,000バイト

ファイルリンクオブジェクト
OLEオブジェクト
圧縮対応
見出語検索キー
Unicode辞書3
6.10
NEWDIC51

同上

1024バイト

256Kバイト

256Kバイト

同上

同上

この仕様書では、上表のUnicode辞書3のみについて述べます。それ以前の辞書については「PDIC辞書形式仕様書」を参照してください。

2.3. 定義

以降現れるC言語の型宣言などは次のようになっています。

typedef unsigned char uchar;

typedef unsigned char byte;

typedef unsigned short ushort;

typedef unsigned short word;

typedef unsigned int uint;

typedef unsigned long ulong;

3. Unicode(BOCU) 辞書 (Hyper辞書形式 Ver.6.00, Ver.6.10)

Unicodeに対応した辞書形式です。文字コードにはBOCU方式の圧縮を行ったUnicodeを用います。BOCUはBinary-Ordered Compression for Unicodeの略で、Unicodeに向いた簡単で便利な圧縮方法です。

  • 文字コードはすべてBOCU1 encoding

  • 各項目の最大バイト数の制限を緩和(カッコ内は旧バージョン時)

    • 見出語 1,024(248)バイト

    • 訳語 256K (3,000) バイト

    • 用例 256K(20,000) バイト

    • 発音記号 1,000 (1,000) バイト

  • 格納できる文字数は文字の種類と圧縮後のサイズに依存するため不定

Ver.6.00とVer.6.10の違いは登録できる文字数の最大長です。

3.1. BOCU-1圧縮方式

指定されたところを除き、文字コードにはBOCU-1 Encodingを使用しています。

(BOCUの詳細についてはhttp://www-6.ibm.com/jp/developerworks/unicode/010921/j_u-binary.html などを参考)

BOCUの特徴は、参考URLに記載されている通り、

  • 欧米文字はほぼ1バイト(UTF-8とほぼ同等)

  • 日本語ではほぼ2バイト(UTF-8なら3バイト)

  • バイナリ—オーダーが保存される(文字列ソートにおける前後関係を圧縮したまま調べることができる)

という特徴があり、辞書へ保存するには適した形式です。

さらに、

  • UTF-8やUTF-16といったエンコーディングに依存せず、同等に対応できる(CodePointそのものを扱っているため)

  • エンディアンに依存しない

  • 文字列終端はシングルバイトの’0’で表す

という特徴もあります。

欠点としては、圧縮伸長処理が必要になります。しかしBOCUは単純な差分による圧縮方式であるため、ディスクアクセスに比べれば小さいオーバーヘッドで済み、パフォーマンスに大きな差はないはずです。

3.1.1. BOCU-1の圧縮効率と検索速度

例えばShiftJISで書かれた英和辞書テキストファイルをUnicodeへ変換しBOCU-1圧縮した場合、だいたい同じサイズくらいになるはずです。

検索にかかる時間についてもBOCU-1の伸長処理が余計にかかるため検索がほんの少し遅くなりますが、ディスクアクセスへの時間が支配的であるため無視できます。仮にディスクをRAMDISKなど高速なデバイスにした場合でも、辞書全体の処理に比べればBOCU-1の伸長処理は非常に小さいものと思われます。

3.2. 辞書全体の構成

ヘッダー部

固定長(1,024バイト)

拡張ヘッダー部

可変長(最大約4Gバイト(理論値)) 新規作成時は0バイト。

インデックス部

可変長(1,024バイト単位) 何もデータが無いと0バイト。最大1,024×32,767 = 32M

データ部

可変長(1,024バイト単位) 1,024バイトを1物理ブロック単位とする インデックス部により論理ブロック番号から物理ブロック番号にマッピングされる。 1つの論理ブロックには連続した複数の物理ブロックを示すことができる。 この場合の連続ブロック数は32,767個までなので、32,767×1,024= 33,553,408(32MB)バイトが最大の1つの論理的なブロックとなる。 物理ブロック番号は理論上は最大 2,147,418,112(2G)、実際はファイルサイズの制限があるためそれ以下となる。

3.3. 見出語検索キー

3.4. ヘッダー部

ヘッダー部は1,024バイトの固定長

名前

説明

headername

char *100

ヘッダー文字列。とくに意味はないが、以下のような文字列が必ず入る。 “ =============== Dictionary for PDIC ===============   “ (ASCII encoding)

dictitle

char *40

辞書名。現在は未使用でNULLでパディング(BOCU1 encodingを使用)

version

short

辞書のバージョン。上位バイトはメジャー番号、下位バイトはマイナー番号

0x0600 : Ver.6.00

0x0610 : Ver.6.10

lword

ushort

見出語の最大長。現在未参照。

248 : Ver.6.00

1,024 : Ver.6.10

ljapa

ushort

訳語の最大長。現在未参照。

10,000 : Ver.6.00

262,144 : Ver.6.10

block_size

ushort

データブロックの1ブロックの長さを示す。

1,024に固定

index_block

ushort

インデックスのサイズをブロック数であらわしたもの。

1ブロックは1,024バイト

インデックス部のサイズは、index_block * block_sizeで求めること。 このフィールドはNEWDIC,NEWDIC2と名前が同じでも扱いがまったく異なるので 注意が必要。

header_size

ushort

ヘッダーのサイズ。1,024固定

index_size

short

未使用

empty_block

short

未使用

nindex

short

未使用

nblock

short

未使用

nword

ulong

登録単語数

dicorder

byte

見出語の登録順 現在のPDICはコード順のみをサポート

0

コード順

1

大文字・小文字同一視順

2

辞書順

3

降順

dictype

byte

辞書の属性 以下のフラグの組み合わせ

0x01

バイナリの圧縮を行っている

0x08

BOCU-1方式の圧縮を利用

0x10

Unicodeを使用している

0x20

多国語辞書(いずれ削除)

0x40

暗号化

0x80

ツリービューモード用の辞書

attrlen

byte

属性長(1に固定)

os

byte

使用OS

0x00

DOS,Windows,OS/2(x86系), 改行はCR,LF

0x01

Mac

0x02

UNIX - SJIS系

0x03

UNIX – EUC系

0x04

UNIX - JIS系

0x20

BOCU-1 encoding

olenumber

long

最新のOLEオブジェクト番号

dummy_lid

10byte

(予約領域)

index_blkbit

byte

インデックス部の物理ブロック番号のビット数(0:16bit,1:32bit)

dummy0

byte

(予約領域)

extheader

ulong

拡張ヘッダーサイズ(バイト単位)

empty_block2

long

先頭空きブロック番号 ない場合は-1(0xFFFFFFFF)

nindex2

ulong

インデックス要素の数

nblock2

ulong

使用データブロック数

cypt

8byte

暗号コード

update_count

ulong

辞書更新回数(LAN共有時に使用)

dummy00

4byte

(予約領域)

dicident

8byte

辞書識別子(ランダムな8バイトの数値)

derefid

8byte

逆リファレンス用辞書識別子

Ver.6.10で廃案

dummy

24byte

ヘッダー部パディング

※DicTypeのUnicode(UTF-16)用辞書ビットは立ちません

3.4.1. 辞書識別子

NEWDIC3

Version.5で追加された新しいヘッダー項目です。ランダムな8バイト(64ビット)の数値が格納されます。この識別子は辞書新規作成時に与えられ、それ以降は原則として変更されません。この識別子は、ファイル名が変更されても同一の辞書であるかどうかの判断を必要とする場合に利用します。ただし、ファイルコピーで辞書を複製した場合は同一の識別子となるため、完全な識別方法として利用することはできません。

※プログラミング上の注意※

乱数の発生方法に注意してください。例えば、

srand(time(NULL)); for(i=0;i<8;i++)dicident[i]=rand();

ですと、srand()だけで識別子が決まることになり、同じ時刻に作成した辞書は必ず同じ識別子になってしまいます。rand関数は乱数のように見えるだけであり、本当の乱数ではありません。

3.4.2. 暗号化のセキュリティについて

暗号化のセキュリティレベルは、プログラミングと暗号理論の両方に精通していれば解読可能なレベルです。

暗号化方式は輸出規制に制限されるような方式を使用していません。

なお、この暗号化はいかなる条件であっても安全であることを保証するものではありません。あくまで作者自身の個人的な判断による能力に基づいた予測に過ぎません。

※2008年時点で暗号化を実装しているものはありません。

3.5. 拡張ヘッダー部

ヘッダー部のextheaderがゼロ以外の場合、拡張ヘッダーが存在します。拡張ヘッダー部はヘッダー部の直後に配置されます。

extheaderではバイト単位でサイズを指定できますが、1,024バイト単位でなければなりません。1,024バイト単位に満たない部分はゼロでパディングされます。(PDICは1,024バイト単位でなくても動作するはずですが、効率が悪くなります)

3.5.1. 拡張ヘッダー部の構成

サイズ

タグ名

データ

2バイト

可変長、 NULL終端

可変長

サイズはバイト単位で、タグ名とデータの合計サイズ。

タグ名は英数字 _ - のみ使用可能。

サイズがゼロの場合は拡張ヘッダーの終端。extheaderはこの終端までのサイズを示す。

タグ名は最大40文字まで。

タグ名の重複が可能。

大文字・小文字を区別する。

タグ名は自由に使えますが、pdic- で始まるタグ名はPDICで予約されています。

拡張ヘッダー部は暗号化の対象になりません。必要な場合は個々のタグで対処する必要があります。

タグ名は辞書の文字コードの種類と一致させる必要がありますが、データ部の文字列は自由です。

3.6. インデックス部

インデックス部ではデータ部の物理的な位置を管理しています。

インデックス部は1,024バイト単位で可変長です。データがまったく登録されていない場合は、0バイトで、最大1,024×32,767=32Mバイトまでです。インデックス部のサイズを制限するものはヘッダー部にあるインデックスブロック数(index_block)です。

物理ブロック番号

ブロック先頭の見出語

-

インデックス部の最後

2バイト or 4バイト

可変長(BOCU-1)

-

4バイト

0から始まる物理ブロック番号を示す

NULL終端 (1byte)

-

NULL4バイト以上であらわす

※物理ブロック番号のサイズはヘッダー部のindex_blkbitで判断します。

物理ブロック番号とブロック先頭の見出語の対がいくつか並び、最後にインデックス部の最後を示す4バイト以上のNULLがあります。インデックス部は1,024バイト単位の可変長であるため、残りはNULLでパディングされています。

物理ブロック番号とは、データ部のブロック番号であり、実際のディスク上の位置を示します。

物理ブロック番号と見出語の組み合わせをインデックス要素と呼びます。このインデックス要素は、見出語のコード順に並びます。(ただし、ヘッダー部のdicorderがコード順でない場合は、この限りではない) 見出語は、データ部の各ブロックの先頭の見出語をそのまま記憶します。

 インデックス要素は先頭から論理ブロック番号という連続した番号をふります。(0~)ただし、これはプログラム処理上に便宜上用いる値ですので、実際の辞書には存在しません。

インデックス部の物理ブロック番号は、2バイトの場合と、4バイトの場合が存在します。どちらを使用するかは実装依存です。PDICではすべての物理ブロック番号が16bitで表せられる場合は2バイトを、それ以上の場合は4バイトを使用しています。物理ブロック番号が16bitを超える場合というのは、1,024×65535=64Mバイト以上ということですので、ほとんどの場合は2バイトで十分であるといえます。このフィールドが2バイトであるか4バイトであるかは、ヘッダー部のindex_blkbitで示します。

3.6.1. 物理ブロック番号からディスク上の位置を求める

物理ブロック番号からディスク上の位置へ変換するには以下の式を用います。

(ディスク上の位置)=(ヘッダーサイズ)+(拡張ヘッダーサイズ)+(インデックスサイズ)+(データブロック長)*(物理ブロック番号)

通常、各項目の値は次のとおりになります。

ヘッダーサイズ

1,024byte

拡張ヘッダーサイズ

0byte以上

インデックスサイズ

index_block * block_size

データブロック長

block_size

インデックス部で注意するところは可変長である点です。インデックス部のすぐ後ろがデータ部ですから、インデックス部を拡張したい場合、データ部の先頭のブロックを移動する必要があることです。さらに、データ部のオフセットがずれたり、物理ブロック番号もずれます。そして最悪なことに空きブロックのリンクは絶対物理ブロック番号でリンクしているため、すべて更新する必要があります。PDICの場合は、空きブロックを必要とするとき、すべての空きブロックリンクを読み込み、メモリ内部で相対物理ブロック番号による片方向リンクリストで管理するため、あまり気にすることなく実装できています。通常、インデックスの更新処理が必要なときは、空きブロックリンクをたどることが多い、ということから重要な問題ではないと思います。また、プログラム内部で絶対物理ブロック番号を保持している場合も、それらをすべて変更しなければならないということも忘れないでください。

  • この仕様は、PDICのプログラムを簡略化するためです。本当は相対物理ブロック番号のほうがsmartであるのは間違いないのですが…。

  • 空きブロックリンクはたとえ相対物理ブロック番号でやっていたとしても、一括登録や一括削除では問題が生じます。何が原因かというと、空きブロックが多数出ることが予想されることです。そうなると、空きブロック更新だけで、かなり時間がかかります。PDICではそんなことはない?実はPDICでは、あるタイミングで空きブロックを無くす処理をやっています。この処理は空きブロックをなくすと同時に辞書サイズも小さくしてくれます。この処理は「重そう」と思うかもしれませんが、意外と軽く、まとめてやるより、少しずつ暇があったら辞書を“簡単に”最適化したほうが速度、サイズともに有利であることがわかりました。

3.7. データ部

データ部には見出語、訳語、用例などの実際のデータが記憶されています。

データ部の構成には大きく分けて2種類有ります。見出語と訳語のみでよい場合と、それ以外の用例、発音記号などを必要とする場合があります。便宜上、前者を基本構成、後者を拡張構成と呼びますが、拡張構成は基本構成に拡張部を付け加えた形になっています。基本構成と拡張構成の区別はこれから述べる見出語属性のフラグによって判断します。

データ部には見出語、訳語、用例などの実際のデータが記憶されています。データ部は1,024バイト単位で管理され、これをブロックと呼びます。

データ部の種類には「使用ブロック」と「空きブロック」があります。空きブロックはヘッダー部のempty_block2が先頭空きブロックの物理ブロック番号を示し、以降、片方向リストで空きブロックをリンクしています。空きブロックが存在しない場合、empty_block2は0xfffffffで、空きブロックリンクの最終ブロックのリンク先も0xffffffffになっています。リンク先は、物理ブロック番号で示しています。ちなみに、PDICの最適化処理というのは、空きブロックを無くし、データブロックを単語順に並び換える処理を行っています。

使用ブロックの構成には大きく分けて2種類有ります。見出語と訳語のみでよい場合と、それ以外の用例、発音記号などを必要とする場合があります。便宜上、前者を基本構成、後者を拡張構成と呼びますが、拡張構成は基本構成に拡張部を付け加えた形になっています。基本構成と拡張構成の区別はこれから述べる見出語属性のフラグによって判断します。

3.7.1. 空きブロック

NULL

空きブロックリンク情報

2バイト

4バイト

空きブロックであることを示す0x0000が入っている

次の空きブロックへの物理ブロック番号

空きブロックはヘッダー部のempty_block2の示すブロックから、空きブロックリンク情報をもとに片方向リンクしています。最終空きブロックの空きブロックリンク情報は0xffffffffです。

空きブロックは連結ブロックのある使用ブロックとは異なり、必ず1ブロック単位でリンクされて構成されています。(PDICの場合1,024バイトが1ブロック)

リンクは物理的にデータブロック部の先頭から後ろに順番に並んでいる必要はありません。(たとえば、空きブロック番号100の次のリンクが30であってもかまわない)

インデックス部の拡張に伴う、先頭データブロックの移動のときには、empty_block2も変わることに注意してください。

PDICでは、使用ブロックを空きブロックにする際、先頭の6バイトを変更する以外は、NULLパディングなどをしません。これは、空きブロックを使用ブロックに復活させることを考えてのことですが、実際は利用していません。つまり、バイナリエディターで空きブロックを見てもきれいにNULLパディングされていません。

3.7.2. データブロック構成

使用ブロック数

フィールドデータ (複数)

フィールドデータ

終端

2バイト

可変長

2バイト or 4バイト

0の場合は空きブロックであることを示す。

1つのフィールドに1つの見出語が登録される

データブロックの最後をNULL2バイト or 4バイト以上で示す。

最上位ビットはフィールド内のフィールド長のサイズを示す

2バイトか4バイトかはフィールド長のサイズによる

PDICの場合、最小ブロック単位は1,024バイトですが、それを複数連結することによって、大きいデータを登録できるようにしています。使用ブロック数というのはこの連結の個数を示しています。

使用ブロック数は、最大32,767個であるため、32,767×1,024=32Mバイトまで。ただし、最上位ビットはこれから述べるフィールド内のフィールド長のサイズを示します。最上位ビットが0の場合は、フィールド長は2バイトであり、最上位ビットが1の場合は、フィールド長が4バイトであることを示しています。

フィールド長が4バイトである場合は、1つのインデックスに対して1つのデータを割り当てなければなりません。つまり、1つのデータブロックには1つのデータしか登録できません。効率を考え、64Kバイト以下のデータは2バイトのフィールド長を、64Kバイト以上のデータは4バイトのフィールド長をそれぞれ使用するようにします。また、フィールド長が4バイトの場合、それに合わせてこれから述べるリンクデータのデータ長を表わすビット数も2バイトから4バイトに変わることも注意してください。

3.7.3. データ部基本構成

次表に1つの見出し語の基本構成を示す。

名称

サイズ

備考

フィールド長

2バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

  • 見出語部の圧縮している長さ(バイト単位)を示す

見出語属性

1バイト

  • 0xFFである場合はリファレンス登録語

見出語

可変長NULL終端

圧縮長を除いた残りの見出語部分 BOCU1 encoding

訳語

可変長NULL終端無し

BOCU1 encoding

見出語部は、見出語キーと見出表示部に分かれる。

“見出語キーt見出表示部”

となる。見出表示部を省略した場合は、見出語キーと見出表示部は同一であるとして扱う。

→期待したとおりの順番にソートされないため廃案

訳語部、用例部、オブジェクトタイトルなどテキストを使用する部分はすべてBOCU encodingを用いる。

見出語部は圧縮されています。圧縮は同一のデータブロックにおいて、直前の見出語との差分を取ることによって行っています。例えば、データブロックの先頭の見出語がABCであり、次の見出語がABDEFだった場合は、2番目の見出語部に入る文字列はABDEFではなく、DEFとなり、圧縮長は2となります。さらにABDGという見出語が続いた場合は、圧縮長が3となり、見出語部に入る文字列はGとなります。

データブロック先頭の見出語の圧縮長は必ず零になります。

注意:ツリービュー用の辞書では、圧縮長は0、見出語はNULL終端のみとなっています。

見出語圧縮の例

見出語

圧縮長

圧縮後の見出語

1番目

ABC

0

ABC

2番目

ABDEF

2

DEF

3番目

ABDGD

3

GD

4番目

AGDE

1

GDE

データ部(リファレンス登録語):→Ver.6.10で廃案

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない)

ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さ(バイト単位)を示す

見出語属性

1バイト

0xFF

見出語

可変長NULL終端

圧縮長を除いた残りの見出語部分

BOCU1 encoding

リファレンス語

可変長NULL終端

この見出語が参照する別の見出し語

見出し語の表示部と同じ場合は省略される。

複数のリファレンス語を並べることが可能。

BOCU1 encoding

3.7.4. 拡張構成

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から拡張終了までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さを示す

見出語属性

1バイト

見出語

可変長NULL終端

訳語

可変長NULL終端あり

BOCU-1で圧縮されている場合は2バイト単位でアライメントをとる。

拡張属性1

1バイト

Reserved

[STRIKEOUT:1バイト]

0x00

拡張内容1

可変長

拡張属性によって内容は異なる

拡張属性2

1バイト

Reserved

[STRIKEOUT:1バイト]

0x00

拡張内容2

可変長

拡張終了

1バイト

0x80

[STRIKEOUT:Reserved]

[STRIKEOUT:1バイト]

0x00

———————————- 旧形式

3.7.5. 拡張構成

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から拡張終了までのバイト単位の長さ(フィールド長、圧縮長は含めない)

ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さを示す

見出語

可変長NULL終端

見出語属性

1バイト

前述

訳語

可変長NULL終端あり

拡張属性1

1バイト

後述

拡張内容1

可変長

拡張属性によって内容は異なる

拡張属性2

1バイト

拡張内容2

可変長

拡張終了

1バイト

0x80

拡張部の特徴としては、バイナリデータ、データの圧縮などが可能になっています。また、拡張属性にはまだ未使用のフラグが残っているため、今後更に拡張される可能性があります。

拡張属性

数値

0x01

用例

0x02

発音記号

0x03

未定義

0x04

リンクデータ

0x05~0x0f

未定義

0x10

バイナリデータフラグ

0x20

未定義

0x40

圧縮フラグ

0x80

拡張終了

拡張属性は下位4bitが項目の種類、上位4bitが何らかのフラグであることを示します。

フラグによってさらに、拡張部の構成は異なります。

拡張部の構成は非常に複雑です。もし、すべての拡張部を必要としない場合は、0x10のフラグだけを見て、スキップすることができます。つまり、0x10がなければNULL終端テキストであると判断し、0x10がある場合は指定されたサイズだけスキップすれば済みます。

3.7.6. 拡張構成

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から拡張終了までのバイト単位の長さ(フィールド長、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さを示す

見出語

可変長NULL終端

見出語属性

1バイト

前述

訳語

可変長NULL終端あり

拡張属性1

1バイト

後述

拡張内容1

可変長

拡張属性によって内容は異なる

拡張属性2

1バイト

拡張内容2

可変長

拡張終了

1バイト

0x80

拡張部の特徴としては、バイナリデータ、データの圧縮などが可能になっています。また、拡張属性にはまだ未使用のフラグが残っているため、今後更に拡張される可能性があります。

3.7.7. 拡張部の構成1-バイナリデータフラグ、圧縮フラグ、拡張終了フラグがない場合

この場合、NULL終端のあるテキストデータであると判断します。

拡張属性

1バイト

0x00~0x0f

テキストデータ

NULL終端有り

圧縮されていない用例や、発音記号はこのフォーマットです。

拡張部の構成2-バイナリデータフラグのみがある場合

拡張属性

1バイト

0x10~0x1f

サイズ

2バイト or 4バイト

拡張データの長さをバイト単位で示す

拡張データ

可変長

圧縮データや、リンクデータがこのフォーマットになります。

拡張部の構成3-圧縮フラグありの場合

拡張属性

1バイト

0x50~0x5f

サイズ

2バイトor4バイト

非圧縮長から圧縮データの最後までのバイト単位の長さを示す

非圧縮長

1バイト

非圧縮データのバイト単位の長さ

非圧縮データ

可変長

圧縮ヘッダー

可変長

圧縮データ

可変長

圧縮ありでは、必ずバイナリデータフラグが必要です。したがって、0x50~という拡張属性になります。

非圧縮長は1バイトであらわすため、255バイトを超える長さにはできないことに注意してください。

圧縮ヘッダーにはリンクデータの一部の内容が入ることがあります。(拡大率、アスペクト比など)

圧縮内容のフォーマットは省略

3.7.8. リンクデータの構成

拡張属性にリンクデータがある場合はさらにフォーマットが定められています。

リンクデータの構成1-非圧縮時

拡張属性

1バイト

0x14

サイズ

2バイト or 4バイト

リンクタイプ

1バイト

ID

4バイト

タイトル

可変長NULL終端有り

データ部

可変長

リンクタイプ

数値

意味

0x00

未定義

0x01

OLE

0x02

ファイルリンク

0x03

音声データ

0x04

DDB(暫定)

0x05

DIB(暫定)

0x06

RTF(暫定)

0x07~0xff

未定義

リンクデータの構成2-圧縮時

拡張属性

1バイト

0x14

サイズ

2バイト or 4バイト

非圧縮長

1バイト

リンクタイプからタイトルの最後までのバイト単位の長さ

リンクタイプ

1バイト

ID

4バイト

タイトル

可変長NULL終端有り

圧縮ヘッダー

可変長

データ部(圧縮データ)

可変長

さらにさらに、リンクデータのデータ部はリンクタイプによって異なります。

ここではデータ部のみを示します。

リンクデータの構成1-OLEデータの場合

省略

リンクデータの構成2-ファイルリンクデータの場合

省略

例:見出語、訳語、用例がある場合

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から訳語の最後までのバイト単位の長さ

見出語

可変長NULL終端

見出語属性

1バイト

訳語

可変長NULL終端無

拡張属性(用例)

1バイト

用例

可変長NULL終端

拡張終了

3.8. リファレンス登録語→Ver.6.10で廃案

Ver.6から新たに追加された機能である。たとえば、

take A for BAをBだと思う

という見出し語および訳語を通常の登録語として登録し、リファレンス登録語として、

forttake A for B

を登録する。

“for”でインクリメンタルサーチを行うと、”forttake A for B”が一覧表示に現れ、実際に表示される内容は

take A for BAをBだと思う

となる。

さらにこの登録語を編集すると”take A for B”という見出し語の訳語が編集されることになる。

もし、見出し語”take A for B”を削除した場合は、”forttake A for B”のリファレンスはリンク切れとなり、エラーが表示される。

take A for B<<reference link error>>

エラーの対処方法はアプリに依存。

3.9. 逆リファレンス辞書→Ver.6.10で廃案

辞書編集者が主に利用する機能である。

“take A for B”の”for”を”as”に変更したい、という場合、これまで述べた辞書形式では辞書をすべて検索しなければならず、非常に時間がかかる(辞書が大きい場合)。それを高速化するための逆リファレンス辞書である。

  • 辞書形式はPDIC辞書形式(Ver.6)

  • 必要な場合のみ作成する

  • 作成されたら本辞書と常に整合性を保つ

  • 整合性をチェックするために、ヘッダー部の逆リファレンス辞書識別子を用いる

  • 不整合と判断された場合は、最初から作り直す

  • データ形式はリファレンス登録語と同じ

3.10. PDICにおけるデータブロックの分割方法

ここでは、辞書の制御で一番難しい、データブロックの分割方法について述べます。この手のデータベースを扱ったことがない方にはピンと来ないかもしれませんが、この処理は登録の速度や格納率に大きく影響します。

辞書ファイルのサイズを抑えるためには、データブロックいっぱいにデータを詰め込み、インデックス部をなるべく小さくすることにあります。

辞書に見出語を登録する際に、見出語が昇順で順番に登録される場合は、かなり高い格納率でデータブロックを埋めていくことができますが、下手をすると未使用領域が大きくなってしまいます。NEWDIC2までは、この点に問題があり、色んな圧縮を用いて辞書のサイズを小さくしても、生のテキストデータより若干大きくなっていました。

また、逆にデータブロックを大きくしすぎると、検索速度が落ちてしまいます。速度とサイズのトレードオフが重要です。

3.10.1. データブロックの分割の基準 - 開発者メモ

この基準を決めるには、検索速度と辞書サイズとのバランスを考える必要があります。

辞書の検索速度はインデックス部とデータ部の検索で決まります。インデックス部はB-treeで検索、データブロック部は逐次検索であるので、 :math:` mathcal{O}(log Ni+ bar{Nd})` のオーダで検索されます(PDICでは、インデックス部がメモリ上、データ部がディスク上にあるのでこんなに簡単ではないのですが)。 ここで、 Ni はインデックス要素の個数、 \bar{Nd} は1つのデータブロックに入っている見出語の個数の平均、logの基底は2です。 \log Ni は小さいので、 \bar{Nd} によって、検索速度、辞書サイズに影響します。( Ni bar{Nd}` に依存する)

また、辞書サイズTは次のような式で求められます。

T=\bar{S} \mathsf X Ni + \bar{Ni}\mathsf X Ni

\bar{S} は1つのデータブロックのサイズの平均、 \bar{Li} はインデックスの要素の平均長です。ちなみにデータブロックの平均格納率 \bar{R}

\bar{R}=\frac{\bar{Nd}\mathsf X \bar{Ld}}{\bar{S}\mathsf X Ni}

です。

\bar{Ld} は、1つの単語の平均長です(単語といっても、訳語などすべてのデータを含め、見出語圧縮や属性、フィールド長なども含めています)。

ここで、整理してみますと、

  • \bar{Nd} は小さいほうが検索が速い

  • \bar{R} は大きいほうが辞書サイズが小さくなる

\bar{R} は処理の結果得られるものと考えると(分割の基準というより、分割時の処理の仕方といえるので)、\bar{Nd} の制御が非常に重要となります。

次に、この \bar{Nd} は小さいほうがよいわけですが、小さすぎるとインデックス部が大きくなってしまい、辞書の使用効率の低下、メモリの使用量の増加、下手をするとインデックス部がいっぱいになったり、インデックス部だけでディスクが満杯になる可能性があります。 また、この \bar{Nd} は常に一定値ではなく、辞書の大きさ(登録単語数)に依存したほうが良いと考えられます。 それは、\log Ni\bar{Nd} との関係を一定にするためです。つまり、

\log Ni = \alpha\bar{Nd}

(αは一定値) という関係式で考え、登録単語数を Nr とすると、

\bar{Nd}\mathsf X Ni
= \bar{Nd} \mathsf X 2^{\alpha\bar{Nd}}

となるように分割を制御します。

なお、αの値は実際のプログラミングに依存するので経験に依存します。

もう一つここで考慮しなければならないのは、Nr が一定値ではなく、変動値であるという点です。 しかし、これはオーダレベルの話ではないので、\alpha に含まれるものとして考えても問題ないと思います。 (まてよ、αに小数点は使えないなぁ…(^^;)

次に、単語の長さ Ld を無視してきましたが、この項は理論式には現れないものの、 実際には検索速度に影響を与えます。 つまり、Ld が非常に大きくなると、ディスクへのアクセス時間(など)が長くなり、これがミスヒットした場合のペナルティが大きくなるためです。しかし、これもプログラムに依存する値なので、詳しくは述べません。

結論としては、

  • 1つのデータブロックの長さが \bar{Nd} 未満であったらブロック拡張

  • 1つのデータブロックの長さが \bar{Nd} を超えたらブロック分割

とします。ただし、 \bar{Nd} 未満であっても、データブロックの長さが Ld に関係した値を超えた場合も分割するとします。逆に、 \bar{Nd} 以上であっても、最小ブロック単位以下であったら分割しません(分割すると格納率が低下するため)。

 ちなみに、PDICではαを1/16(かな?)にしています。この値はブロックを分割したときの理想値にしなければならないことに注意しなければなりません。

3.10.2. データブロックの分割方法

前項で分割の基準が決まったので、次は分割方法です。ここで重要なのはデータブロックの平均格納率です。格納率を向上させるために、データブロック分割点は格納率が最も良くなるところにすればよいことになります。

これで実際のプログラミングには入れるわけですが、このブロック分割は非常に厄介な処理です。もし、登録プログラムを作成される方は、以上の内容を十分理解し、どのような変更を行ったら辞書のどの部分に影響を与えるのか、よく考えながらプログラミングされてください。まず、プログラムの仕様作成で普段の2倍の時間をかけ、一点の曇りのないものに仕上げ、それから普段の2倍の時間をかけて慎重にプログラミングを行ってください。それでも、通常のプログラムの数倍のバグが出てきます。(作者もここをしっかり押さえずにやっていたら、デバッグに恐ろしいほどの時間がかかりました(^^;;)。とにかく、いろんな条件や場合分けが存在しています。

4. Unicode辞書 Ver.5.00 の構造

4.1. データブロック部

基本構成

フィールド長

2バイト or 4バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さ(文字単位)を示す

見出語

可変長NULL終端

圧縮してある

見出語属性

1バイト

後述

訳語

可変長NULL終端無し

4.1.1 拡張構成

名称

サイズ

備考

フィールド長

2バイト or 4バイト

見出語から拡張終了までのバイト単位の長さ(フィールド長、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さを示す

見出語

可変長NULL終端

見出語属性

1バイト

前述

訳語

可変長NULL終端あり

拡張属性1

1バイト

後述

拡張内容1

可変長

拡張属性によって内容は異なる

拡張属性2

1バイト

拡張内容2

可変長

拡張終了

1バイト

0x80

拡張部の特徴としては、バイナリデータ、データの圧縮などが可能になっています。また、拡張属性にはまだ未使用のフラグが残っているため、今後更に拡張される可能性があります。

5. Unicode(BOCU) 辞書 (Hyper辞書形式 Ver.5)

データ部:

フィールド長

2バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さ(バイト単位)を示す

見出語属性

1バイト

見出語

可変長NULL終端

圧縮長を除いた残りの見出語部分 BOCU1 encoding

訳語

可変長NULL終端無し

BOCU1 encoding

  1. 訳語部、用例部、オブジェクトタイトルなどテキストを使用する部分はすべてをBOCU encodingを用いる。

  2. 見出語属性の位置が異なる(見出語属性が見出語圧縮長の直後に位置している)

6. Unicode(UTF-8) 辞書

データ部:

フィールド長

2バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さ(バイト単位)を示す

見出語属性

1バイト

見出語

可変長NULL終端

圧縮長を除いた残りの見出語部分

訳語

可変長NULL終端無し

BOCU-1で圧縮

  1. 見出語部はUTF-8のコードをそのまま使用する(BOCU-1による圧縮は行わない)。

  2. 訳語部、用例部、オブジェクトタイトルなどテキストを使用する部分はすべてをBOCU-1(Binary-Order Compression for Unicode)による圧縮を行う。(BOMは付加しない)

  3. フィールド部が異なる(見出語属性が見出語圧縮長の直後に位置している)

7. Unicode(UTF-16)対応辞書

データ部

フィールド長

2バイト

見出語から訳語の最後までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さ(文字単位)を示す

見出語属性

1バイト

見出語

可変長NULL終端 (Unicode)

圧縮してある

訳語

可変長NULL終端無し (Unicode)

BOCU-1で圧縮されている場合は2バイト単位でサイズのアライメントをとる。

発音記号、用例、オブジェクトタイトルも同様にUnicode NULL終端とする。

拡張構成

名称

サイズ

備考

フィールド長

2バイト

見出語から拡張終了までのバイト単位の長さ(フィールド長、見出語属性、圧縮長は含めない) ここのサイズはデータブロックの先頭の最上位ビットによって決まる。

圧縮長

1バイト

見出語部の圧縮している長さを示す

見出語属性

1バイト

見出語

可変長NULL終端

訳語

可変長NULL終端あり

BOCU-1で圧縮されている場合は2バイト単位でアライメントをとる。

拡張属性1

1バイト

Reserved

1バイト

0x00

拡張内容1

可変長

拡張属性によって内容は異なる

拡張属性2

1バイト

Reserved

1バイト

0x00

拡張内容2

可変長

拡張終了

1バイト

0x80

Reserved

1バイト

0x00

  • 詳細な説明は省略

  • 現在のところ、フィールド長が4バイトになる場合は未定義です。

  • バイナリデータの圧縮方式はShiftJIS辞書とは異なります。(詳細は省略)

  • 拡張内容がテキストである場合は、BOCU-1による圧縮を行います(DicTypeに0x08がある場合)

8. 履歴

2007.7.2

0.90版

9. 著作権

この文書の著作権はTaN (sgm00353@nifty.ne.jp) にあります。

この文書は内容を改変しない限り、フリーであり、再配布は自由です。

この文書によって生じるいかなる損害の責任は負いません。

この文書を元にソフトウェアを作成・配布することに許可は必要ありません。制限も一切ありません。

この文書に従った辞書については著作権上の何の制限もありません。