/*
* "123" "ABC" のような辞書にのってない
* 文字列に対する問合せの場合は全ての候補をここで生成する
* 上記の他に郵便番号へのアクセスも行なう
*
* Copyright (C) 2001-2005 TABATA Yusuke
* Copyright (C) 2004-2005 YOSHIDA Yuichi
*
*/
/*
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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <anthy/anthy.h> /* for ANTHY_*_ENCODING */
#include <anthy/conf.h>
#include <anthy/xstr.h>
#include <anthy/xchar.h>
#include "dic_main.h"
#include "dic_ent.h"
/* ext entry */
static struct seq_ent unkseq_ent;/*未知文字列たとえば英文字列とか*/
static struct seq_ent num_ent;/*数字など*/
static struct seq_ent sep_ent;/*セパレータなど。*/
/* ext entryのwtype*/
static wtype_t wt_num;
static xchar narrow_wide_tab[]= {WIDE_0, WIDE_1, WIDE_2,
WIDE_3, WIDE_4, WIDE_5,
WIDE_6, WIDE_7, WIDE_8, WIDE_9};
static int kj_num_tab[]={KJ_0, KJ_1, KJ_2, KJ_3, KJ_4,
KJ_5, KJ_6, KJ_7, KJ_8, KJ_9};
struct zipcode_line {
int nr;
xstr **strs;
};
/* 地名を追加する */
static void
pushback_place_name(struct zipcode_line *zl, char *pn)
{
if (pn[0] == '#') {
return ;
}
zl->strs = realloc(zl->strs, sizeof(xstr *) * (zl->nr + 1));
zl->strs[zl->nr] = anthy_cstr_to_xstr(pn, ANTHY_EUC_JP_ENCODING);
zl->nr++;
}
/* 郵便番号辞書をパースしてスペース区切りを検出する */
static void
parse_zipcode_line(struct zipcode_line *zl, char *ln)
{
char buf[1000];
int i = 0;
while (*ln) {
buf[i] = *ln;
if (*ln == '\\') {
buf[i] = ln[1];
i ++;
if (ln[1]) {
ln ++;
}
} else if (*ln == ' ') {
buf[i] = 0;
i = 0;
pushback_place_name(zl, buf);
} else {
i ++;
}
/**/
ln ++;
}
buf[i] = 0;
pushback_place_name(zl, buf);
}
/* 郵便番号辞書から探す */
static void
search_zipcode_dict(struct zipcode_line *zl, xstr* xs)
{
FILE *fp;
char buf[1000];
int len;
xstr *temp;
char *index;
zl->nr = 0;
zl->strs = NULL;
fp = fopen(anthy_conf_get_str("ZIPDICT_EUC"), "r");
if (!fp) {
return ;
}
/* 半角、全角を吸収する */
temp = anthy_xstr_wide_num_to_num(xs);
index = anthy_xstr_to_cstr(temp, 0);
len = strlen(index);
/* 全部grepする */
while (fgets(buf, 1000, fp)) {
/* 3文字の郵便番号が7文字の郵便番号の頭にマッチしないように */
if (!strncmp(buf, index, len) && buf[len] == ' ') {
/* 改行を消す */
buf[strlen(buf) - 1] = 0;
parse_zipcode_line(zl, &buf[len + 1]);
}
}
free(temp);
free(index);
fclose(fp);
}
/* 郵便番号辞書の情報を解放する */
static void
free_zipcode_line(struct zipcode_line *zl)
{
int i;
for (i = 0; i < zl->nr; i++) {
anthy_free_xstr(zl->strs[i]);
}
free(zl->strs);
}
static int
gen_zipcode(xstr* xs, xstr *dest, int nth)
{
struct zipcode_line zl;
/* 郵便番号辞書から地名を読み取る */
search_zipcode_dict(&zl, xs);
/* 候補を取得する */
if (zl.nr > nth) {
dest->len = zl.strs[nth]->len;
dest->str = anthy_xstr_dup_str(zl.strs[nth]);
free_zipcode_line(&zl);
return 0;
} else {
free_zipcode_line(&zl);
return -1;
}
}
/* 半角の数字から全角の数字を求める */
static xchar
narrow_num_to_wide_num(xchar xc)
{
if (xc > '9' || xc < '0') {
return WIDE_0;
}
return narrow_wide_tab[(int)(xc - '0')];
}
/* 全角の数字から半角の数字を求める */
static xchar
wide_num_to_narrow_num(xchar xc)
{
int i;
for (i = 0; i < 10; i++) {
if (xc == narrow_wide_tab[i]) {
return i + '0';
}
}
return '0';
}
/*
* 一桁の整数を漢数字に変換する
*/
static xchar
get_kj_num(int n)
{
if (n > 9 || n < 1) {
return KJ_10;
}
return kj_num_tab[n];
}
/*
* 4桁分の整数を漢字文字列としてを生成する
*/
static void
compose_num_component(xstr *xs, long long num)
{
int n[4],i;
int a[4] = { 0 , KJ_10, KJ_100, KJ_1000};
for (i = 0; i < 4; i++) {
n[i] = num-(num/10)*10;
num /= 10;
}
/* 10,100,1000の位 */
for (i = 3; i > 0; i--) {
if (n[i] > 0) {
if (n[i] > 1) {
anthy_xstrappend(xs, get_kj_num(n[i]));
}
anthy_xstrappend(xs, a[i]);
}
}
/* 1の位 */
if (n[0]) {
anthy_xstrappend(xs, get_kj_num(n[0]));
}
}
/** 漢数字の文字列を作る */
static int
gen_kanji_num(long long num, xstr *dest)
{
int i;
int n[10];
if (num < 1 || num >= 10000000000000000LL) {
return -1;
}
/* 4桁ずつ配列nにつめる */
for (i = 0; i < 10; i ++) {
n[i] = num-(num/10000)*10000;
num = num/10000;
}
/**/
dest->len = 0;
dest->str = 0;
/* 京の位をつくる */
if (n[3]) {
compose_num_component(dest, n[3]);
anthy_xstrappend(dest, KJ_1000000000000);
}
/* 億の位をつくる */
if (n[2]) {
compose_num_component(dest, n[2]);
anthy_xstrappend(dest, KJ_100000000);
}
/* 万の位をつくる */
if (n[1]) {
compose_num_component(dest, n[1]);
anthy_xstrappend(dest, KJ_10000);
}
/**/
compose_num_component(dest, n[0]);
return 0;
}
static int
get_nr_zipcode(xstr* xs)
{
struct zipcode_line zl;
int nr = 0;
if (xs->len != 3 && xs->len != 7) {
return 0;
}
/* 郵便番号辞書から地名を読み取る */
search_zipcode_dict(&zl, xs);
nr = zl.nr;
free_zipcode_line(&zl);
return nr;
}
static int
get_nr_num_ents(long long num)
{
if (num > 0 && num < 10000000000000000LL) {
if (num > 999) {
/* アラビア数字(そのまま)、アラビア数字(全角半角切替え)、
漢数字、3桁区切り(全角、半角) */
return 5;
} else {
/* アラビア数字(そのまま)、全角半角切替え、漢数字 */
return 3;
}
} else {
/* アラビア数字(そのまま)、全角半角切替え */
return 2;
}
}
/*
* いくつの合成のエントリーがあるか
*/
int
anthy_get_nr_dic_ents_of_ext_ent(seq_ent_t se, xstr *xs)
{
if (se == &unkseq_ent) {
return 1;
}
if (anthy_get_xstr_type(xs) & (XCT_NUM|XCT_WIDENUM)) {
long long num = anthy_xstrtoll(xs);
return get_nr_num_ents(num) + get_nr_zipcode(xs);
}
return 0;
}
/* 文字列の全角半角を交換する */
static void
toggle_wide_narrow(xstr *dest, xstr *src)
{
int f, i;
dest->len = src->len;
dest->str = anthy_xstr_dup_str(src);
f = anthy_get_xstr_type(src) & XCT_WIDENUM;
for (i = 0; i < dest->len; i++) {
if (f) {
dest->str[i] = wide_num_to_narrow_num(src->str[i]);
} else {
dest->str[i] = narrow_num_to_wide_num(src->str[i]);
}
}
}
/* 3桁に区切った数字を生成する */
static int
gen_separated_num(long long num, xstr *dest, int full)
{
int width = 0, dot_count;
long long tmp;
int i, pos;
if (num < 1000) {
return -1;
}
/* 桁数を数える */
for (tmp = num; tmp != 0; tmp /= 10) {
width ++;
}
/* 点の数 */
dot_count = (width - 1) / 3;
/* 格納するのに必要な文字列を用意する */
dest->len = dot_count + width;
dest->str = malloc(sizeof(xchar)*dest->len);
/* 右の桁から順に決めていく */
for (i = 0, pos = dest->len - 1; i < width; i++, pos --) {
int n = num % 10;
/* カンマを追加 */
if (i > 0 && (i % 3) == 0) {
if (full) {
dest->str[pos] = WIDE_COMMA;
} else {
dest->str[pos] = ',';
}
pos --;
}
if (full) {
/* 全角数字 */
dest->str[pos] = narrow_wide_tab[n];
} else {
/* ASCII数字 */
dest->str[pos] = 48 + n;
}
num /= 10;
}
return 0;
}
/*
* nth個めの候補を取り出す
*/
int
anthy_get_nth_dic_ent_str_of_ext_ent(seq_ent_t se, xstr *xs,
int nth, xstr *dest)
{
if (nth == 0) {
/* 無変換文字列 */
dest->len = xs->len;
dest->str = anthy_xstr_dup_str(xs);
return 0;
}
if (se == &unkseq_ent) {
switch(nth) {
case 1:
/* 全角、半角のトグル */
return 0;
}
}
if (anthy_get_xstr_type(xs) & (XCT_NUM|XCT_WIDENUM)) {
long long num = anthy_xstrtoll(xs);
/* 漢数字、アラビア数字、全角半角切替え */
switch(nth) {
case 1:
/* 全角半角を入れ換えたもの */
toggle_wide_narrow(dest, xs);
return 0;
case 2:
/* 漢数字 */
if (!gen_kanji_num(num, dest)) {
return 0;
}
/* break無し */
case 3:
/* 3桁で区切った数字 */
if (!gen_separated_num(num, dest, 0)) {
return 0;
}
/* break無し */
case 4:
/* 3桁で区切った数字(全角) */
if (!gen_separated_num(num, dest, 1)) {
return 0;
}
/* break無し */
default:
/* 郵便番号 */
if (nth >= 5) {
if (xs->len == 3 || xs->len == 7) {
if (!gen_zipcode(xs, dest, nth-5)) {
return 0;
}
}
}
break;
}
return -1;
}
return 0;
}
int
anthy_get_ext_seq_ent_indep(struct seq_ent *se)
{
if (se == &num_ent || se == &unkseq_ent) {
return 1;
}
return 0;
}
/* 活用形を得る */
int
anthy_get_ext_seq_ent_ct(struct seq_ent *se, int pos, int ct)
{
if (anthy_get_ext_seq_ent_pos(se, pos) && ct == CT_NONE) {
/* 品詞が合っていてかつ無活用の場合
(ext_entは活用しない) */
return 10;
}
return 0;
}
/* 品詞を取得する */
int
anthy_get_ext_seq_ent_pos(struct seq_ent *se, int pos)
{
/* ext_entは名詞のみ */
if (se == &num_ent && pos == POS_NOUN) {
return 10;
}
if ((se == &unkseq_ent) && pos == POS_NOUN) {
return 10;
}
return 0;
}
/*
* 辞書にのっていないシーケンスを解析
*/
seq_ent_t
anthy_get_ext_seq_ent_from_xstr(xstr *x, int is_reverse)
{
int t = anthy_get_xstr_type(x);
/* 数字のみで構成されていれば num_ent */
if (t & (XCT_NUM | XCT_WIDENUM)) {
return &num_ent;
}
/* 英数ならunkseq */
if (t & XCT_ASCII) {
return &unkseq_ent;
}
if (t & XCT_KATA) {
return &unkseq_ent;
}
if (!is_reverse) {
/* 逆変換中は漢字候補は作らない */
if (t & XCT_KANJI) {
return &unkseq_ent;
}
}
if (x->len == 1) {
/* 辞書にのってなくて1文字ならセパレータ */
return &sep_ent;
}
return 0;
}
int
anthy_get_nth_dic_ent_wtype_of_ext_ent(xstr *xs, int nth,
wtype_t *wt)
{
int type;
(void)nth;
type = anthy_get_xstr_type(xs);
if (type & (XCT_NUM | XCT_WIDENUM)) {
*wt = wt_num;
return 0;
}
if (type & XCT_KATA) {
*wt = anthy_get_wtype(POS_NOUN, COS_NONE, SCOS_NONE, CC_NONE,
CT_NONE, WF_INDEP);
return 0;
}
return -1;
}
int
anthy_get_nth_dic_ent_freq_of_ext_ent(struct seq_ent *se, int nth)
{
(void)se;
(void)nth;
return 100;
}
int
anthy_get_ext_seq_ent_wtype(struct seq_ent *se, wtype_t w)
{
if (se == &num_ent) {
if (anthy_wtype_include(w, wt_num)) {
/* 数字の場合 */
return 10;
}
return 0;
}
if (anthy_wtype_get_pos(w) == POS_NOUN &&
anthy_wtype_get_cos(w) == COS_NONE &&
anthy_wtype_get_scos(w) == SCOS_NONE) {
/* 名詞、副品詞なし、副々品詞無しにマッチ */
return 10;
}
return 0;
}
void
anthy_init_ext_ent(void)
{
/**/
unkseq_ent.seq_type = 0;
unkseq_ent.nr_dic_ents = 0;
num_ent.seq_type = 0;
num_ent.nr_dic_ents = 0;
sep_ent.seq_type = 0;
sep_ent.nr_dic_ents = 0;
/**/
wt_num = anthy_init_wtype_by_name("数詞");
}
syntax highlighted by Code2HTML, v. 0.9.1