/* * 読みから単語の情報を取得するデータ構造をファイル中に * 出力するためのコード * * データ構造を変更しやすくするためにmkdic.cから分離(2005/7/8) * * output_word_dict()が呼び出される * * Copyright (C) 2000-2006 TABATA Yusuke */ /* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "mkdic.h" extern FILE *page_out, *page_index_out; extern FILE *yomi_entry_index_out, *yomi_entry_out; static int write_word(struct word_entry *we, int encoding) { int count; if (encoding == ANTHY_UTF8_ENCODING) { count = fprintf(yomi_entry_out, "%s", we->word_utf8); } else { char *s = anthy_conv_utf8_to_euc(we->word_utf8); count = fprintf(yomi_entry_out, "%s", s); free(s); } return count; } static int write_freq(FILE *fp, struct word_entry *we) { int count = 0; int freq = we->freq / 100; if (freq != 1) { count += fprintf(fp, "*%d", freq); } return count; } static int compare_word_entry(struct word_entry *prev_we, struct word_entry *we) { if (strcmp(prev_we->wt_name, we->wt_name) || (prev_we->freq / 100) != (we->freq / 100) || prev_we->feature != we->feature) { return 1; } return 0; } /** 一つの読みに対する単語の内容を出力する * 返り値は出力したバイト数 */ static int output_word_entry_for_a_yomi(struct yomi_entry *ye, int encoding) { int i; int count = 0; if (!ye) { return 0; } if (encoding == ANTHY_UTF8_ENCODING) { count ++; fputc('u', yomi_entry_out); } /* 各単語を出力する */ for (i = 0; i < ye->nr_entries; i++) { struct word_entry *we = &ye->entries[i]; struct word_entry *prev_we = NULL; if (i != 0) { prev_we = &ye->entries[i-1]; } /**/ if (!we->raw_freq) { continue; } if (i > 0) { /* 二つ目以降は空白から始まる */ count += fprintf(yomi_entry_out, " "); } /* 品詞と頻度を出力する */ if (i == 0 || compare_word_entry(prev_we, we)) { count += fprintf(yomi_entry_out, "%s", we->wt_name); if (we->feature != 0) { count += fprintf(yomi_entry_out, ","); } count += write_freq(yomi_entry_out, we); count += fprintf(yomi_entry_out, " "); } /* 単語を出力する場所がこの単語のid */ we->offset = count + ye->offset; /* 単語を出力する */ count += write_word(we, encoding); } fputc(0, yomi_entry_out); return count + 1; } /* 2つの文字列の共通部分の長さを求める */ static int common_len(xstr *s1, xstr *s2) { int m,i; if (!s1 || !s2) { return 0; } if (s1->len < s2->len) { m = s1->len; }else{ m = s2->len; } for (i = 0; i < m; i++) { if (s1->str[i] != s2->str[i]) { return i; } } return m; } /* * 2つの文字列の差分を出力する * AAA ABBB という2つの文字列を見た場合には * ABBBはAAAのうしろ2文字を消してBBBを付けたものとして * \0x2BBBと出力される。 */ static int output_diff(xstr *p, xstr *c, int encoding) { int i, m, len = 1; m = common_len(p, c); if (p && p->len > m) { fprintf(page_out, "%c", p->len - m + 1); } else { fprintf(page_out, "%c", 1); } for (i = m; i < c-> len; i++) { char buf[8]; len += anthy_sputxchar(buf, c->str[i], encoding); fputs(buf, page_out); } return len; } static void begin_new_page(int i) { fputc(0, page_out); write_nl(page_index_out, i); } static void output_entry_index(int i) { write_nl(yomi_entry_index_out, i); } /* 読みの文字列からファイル中の位置(offset)を求めるためのテーブルを作る * page_out, page_index_out, yomi_entry_index_outに出力 */ static void generate_yomi_to_offset_map(struct yomi_entry_list *yl) { int i; struct yomi_entry *ye = NULL; xstr *prev = NULL; int page_index = 0; /* 読みから位置(offset)を計算するデータ構造を構成する */ /* まず、最初の読みに対するエントリのインデックスを書き出す */ write_nl(page_index_out, page_index); /**/ for (i = 0; i < yl->nr_valid_entries; i++) { ye = yl->ye_array[i]; /* 新しいページの開始 */ if ((i % WORDS_PER_PAGE) == 0 && (i != 0)) { page_index ++; prev = NULL; begin_new_page(page_index); } /* 読みに対応する情報を出力する */ page_index += output_diff(prev, ye->index_xstr, yl->index_encoding); output_entry_index(ye->offset); /***/ prev = ye->index_xstr; } } /** 単語辞書を出力する * また、このときに辞書中のオフセットも計算する */ void output_word_dict(struct yomi_entry_list *yl) { int entry_index = 0; int i; struct yomi_entry *ye = NULL; /* 各読みに対するループ */ for (i = 0; i < yl->nr_valid_entries; i++) { /* 単語を出力して、ファイル中の位置(offset)を計算する */ ye = yl->ye_array[i]; ye->offset = entry_index; entry_index += output_word_entry_for_a_yomi(ye, yl->body_encoding); } /* 読みの文字列からファイル中の位置(offset)を求めるためのテーブルを作る */ generate_yomi_to_offset_map(yl); /* 最後の読みを終了 */ entry_index += output_word_entry_for_a_yomi(ye, yl->body_encoding); write_nl(yomi_entry_index_out, entry_index); write_nl(page_index_out, 0); /**/ printf("Total %d indexes, %d words, (%d pages).\n", yl->nr_valid_entries, yl->nr_words, yl->nr_valid_entries / WORDS_PER_PAGE + 1); }