0

Visual C/C++ 6 を想定すると、次のような 22399 要素の複雑なデータ構造があります。

{
{ "(SAME", "AS", "U+4E18)", "HILLOCK", "OR", "MOUND"},
{ "TO", "LICK;", {1, 1, 0}, "TASTE,", "A", "MAT,", "BAMBOO", "BARK"},
{ "(J)", "NON-STANDARD", "FORM", "OF", "U+559C", ",", {1, 1, 0}, "LIKE,", "LOVE,", "ENJOY;", {1, 1, 4}, "JOYFUL", "THING"},
{ "(AN", "ANCIENT", {1, 2, 2}, {1, 2, 3}, "U+4E94)", "FIVE"}, 
...
}

これを宣言する最良の方法は何ですか? 私は次のようなことを試しました

char * abbrevs3[22399][] = { ... };

char * abbrevs3[22399][][] = { ... };

しかし、コンパイルは慢性的な何かを鳴らします。

EDIT : データは、特定のユニハン キャラクターの説明のデータベースです。データを圧縮するさまざまな方法を検討してきました。現状では、22399 個のエントリがあり、それぞれにさまざまな数の文字列、または { 略語マーカー、最後に表示された行、最後に表示されたその行の要素 } のトリプレットが含まれる場合があります。

ところで、Greg の話によると、一部の要素が空の文字列であっても、各行に同じ数の要素を含める必要があるかもしれません。そうですか?

編集#2:そして、トリプレットの数値の一部がcharの制限をはるかに超えていることがわかりました。

4

6 に答える 6

4

コードで初期化を行う代わりに、データを XML またはその他の構造化された形式で保存し、それを読み取って解析することを検討します。初期化時に支払うペナルティは、コードの理解のしやすさと保守性の向上という点で十分です。また、各エントリを保持する特定のデータ構造を設計することも検討します。

[編集] 以下の例は、その後の説明を複製しようとしています。

enum EntryType { string = 0, triple = 1 };

typedef struct {
   enum EntryType entry_type;
   union {
      char** string;
      int[3] *triple;
   }
} Entry;

typedef struct {
   Entry *entries;
} Abbreviation;

Abbreviation *abbrevs3;

abbrevs3 = parseAbbreviationData("path-to-abbreviations/abbrevs.xml");
于 2008-10-12T18:33:34.367 に答える
3

C では、配列を宣言するときに最初の次元のみを除外できます。

char * abbrevs3[][22399] = { ... };

これは、コンパイラが「列」を適切にレイアウトできるように、各「行」の大きさを知りたいためです。次元をどのように解釈しても自由なので、次元を引用符で囲みますが、これは 2 次元配列の通常の規則です。

とはいえ、データ構造が実際に何であるか、または初期化しようとしているものは不明です。サンプル データには、いかなる種類のパターンもないようです。

于 2008-10-12T18:15:57.427 に答える
2

私はあなたの新しい投稿を読み、元の投稿を読み直しました。ここでの目標を完全に理解したと思います. 遅くなってしまい申し訳ありません。

質問を言い換えると、元の例の 4 行目:

{ "(AN", "ANCIENT", {1, 2, 2}, {1, 2, 3}, "U+4E94)", "FIVE"},

データを圧縮するために、トリプルを以前に使用した文字列への参照に変換する必要があります。その行は次のようになります。

{ "(AN", "ANCIENT", "FORM", "OF", "U+4E94)", "FIVE"},

目標が圧縮である場合、ここで多くの利益が得られるとは思いません。自己参照トリプルはそれぞれ 3 バイトですが、置換される文字列はヌル ターミネータを含めて合計 8 バイトにすぎず、この行で節約できるのは 2 バイトだけです。そして、それは文字を使用するためのものです。構造が非常に大きいため、参照に int を使用する必要があるため、トリプルは実際には 12 バイトであり、これはさらに悪いことです。この場合、12 文字以上の ASCII 文字を代入することによってのみスペースを節約できます。

私がここで完全にベースから外れている場合は、私を無視してかまいませんが、スペースをトークン化してから重複する単語を削除するというアプローチは、貧乏人のハフマン圧縮のようなものだと思います. アルファベットが最長の共通部分文字列のリストであるハフマン、または他の標準的なテキスト圧縮方法は、おそらくこの問題にうまく機能します。

ただし、何らかの理由でこれがオプションでない場合は、データ内のすべての一意の単語のリストを取得し、それをルックアップ テーブルとして使用すると思います。次に、すべての文字列をインデックスのリストとしてそのテーブルに格納します。2 つのテーブルを使用する必要がありますが、最終的にはより単純になる可能性があり、現在「略語マーカー」として使用している先頭の 1 で使用されているスペースを節約できます。基本的に、略語マーカーはトリプレットではなく単一のインデックスになります。

そう、

const char * words[] = {
    "hello", "world", "goodbye", "cruel"
    };

const int strings[] = {
    { 0, 1 },
    { 2, 3, 1 }
    };

ただし、文字列の長さがほぼ均一でない場合でも、多くのスペースが失われます。

于 2008-10-13T17:49:22.380 に答える
1

ここでの問題は、各行に異なる数の文字列がある C スタイルの文字列の多次元配列を静的に宣言できるかどうかだと思います。したがって、次のようなものです。

const char * arr[][3] =
    {
    {"bla", "bla", "bla"},
    {"bla", "bla" }
    };

一部の言語では、これは「ジャグ配列」と呼ばれます。C および C++ ではこれを行うことができますが、コンパイラはすべての行を同じ長さであるかのように格納するスペースを割り当てたいため、2 番目の配列の 3 番目の項目を初期化しないことになります。これを gcc でテストしたところ、その配列の 3 番目の項目が NULL に設定されていましたが、それを信頼できるかどうかはわかりません。

{1,2,3} のように宣言された配列を C スタイルの文字列としてコンパイラに受け入れさせることはできないと思います。たとえそうで、これらを文字列として扱ったとしても、null で終了していないため、問題が発生します。

他のポスターに同意します。より良いアプローチは、おそらくこのデータを XML、yaml、または取得元のデータベースに保存し、そこにアクセスすることです。これらをソース ファイルで静的に作成する必要がある場合は、データにとって意味のある構造を宣言し、それらの配列を初期化する方がよいでしょう。何かのようなもの:

typedef struct
{
  const char * somestring;
  const char * someotherstring;
  const unsigned int triple[3];
} Abbreviation;

const Abbreviation abb[] =
  {
    {"First Thing", "Second String", {1,2,3} },
    {"Other Thing", "Some String", {4,5,6} }
  };
于 2008-10-12T19:03:34.413 に答える
1

元のデータは約 1.7MB で、1 つは私の雇用主から、もう 1 つは Unicode Consortium からの 2 つのファイル (約 30MB の Unihan.txt) から派生したものです。辞書検索技術を使用して、最も長く最も頻繁に出現する上位 128 の単語の辞書を使用しても、データ サイズはわずか 1.5 MB にまで減少します。おそらく、単語検出をよりインテリジェントにすることで、これを改善できます。これは現在、スペース上の VBScript Split() にすぎません。

準ハフマン アプローチでどれだけ小さくなったかはわかりませんが、1MB よりわずかに小さいと思います。私はこれらすべてを個別のファイルとしてではなく、バイナリで保持したいと考えていました (悪い習慣などについて他の人が言うかもしれませんが)。しかし、現状では、少なくとも C では、すべてが少し難しくなりすぎています。 EuphoriaでBSTRのバリアント配列を作成する方法を理解できます...

編集: 標準の UCN に関して辞書検索を使用しましたが、これはグリフ記述の反復的な性質のためにうまく機能します。ユニハンの問題は、グリフが何を意味するかの説明になってしまうことです。と の間には質的な (そして量的な!) 違いが"VULGAR FRACTION ONE QUARTER"あります"A KIND OF PUNISHMENT IN HAN DYNASTY, NAME OF CHESSMEN IN CHINESE CHESS GAME(SIMPLIFIED FORM, A VARIANT U+7F75) TO CURSE; TO REVILE; TO ABUSE, TO SCOLD"

したがって、辞書検索から離れて、より強力な「圧縮」手法に移行します。

(そして、誰かが「1.7MB の大きな問題は何ですか?」と言う前に、私は 16K RAM が多かった時代から来ました。そして、いずれにせよスペースの制約があります。)

于 2008-10-14T01:20:44.637 に答える
0

物語はまだ終わっていないようです。私は最終的にすべてを不規則な配列に変えてしまいましたint。しかし、それでは、トリプレットの背後にある自己参照メカニズムが依存していた行内のアイテムのアイデアが失われます.

不規則な配列のサポートが優れているため、CではなくEuphoriaを使用することを検討しています。Euphoria を使用して標準の DLL を構築することができ、BSTR のバリアント配列を返して Typelib を記述する方法を理解したら ...

C に固執して、トリプレットを 3 つの int の連続として保存し、文字列を整数としてキャストされたポインターとして保存できると思います。そうすれば、最初に自己参照ディクショナリを作成した VBScript を大幅に書き直す必要がなくなります。

于 2008-10-13T15:09:46.540 に答える