1 /* 2 * migemo.c - 3 * 4 * Written By: MURAOKA Taro <koron@tka.att.ne.jp> 5 */ 6 module migemo_d.migemo; 7 8 9 private static import core.memory; 10 private static import core.stdc.ctype; 11 private static import core.stdc.stdio; 12 private static import core.stdc..string; 13 private static import migemo_d.charset; 14 private static import migemo_d.filename; 15 private static import migemo_d.mnode; 16 private static import migemo_d.romaji; 17 private static import migemo_d.rxgen; 18 private static import migemo_d.wordbuf; 19 private static import migemo_d.wordlist; 20 21 //#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN32__) 22 // #define MIGEMO_CALLTYPE __stdcall 23 //#else 24 // #define MIGEMO_CALLTYPE 25 //#endif 26 27 public enum MIGEMO_VERSION = "1.3"; 28 29 /* for migemo_load() */ 30 public enum MIGEMO_DICTID_INVALID = 0; 31 public enum MIGEMO_DICTID_MIGEMO = 1; 32 public enum MIGEMO_DICTID_ROMA2HIRA = 2; 33 public enum MIGEMO_DICTID_HIRA2KATA = 3; 34 public enum MIGEMO_DICTID_HAN2ZEN = 4; 35 public enum MIGEMO_DICTID_ZEN2HAN = 5; 36 37 /* for migemo_set_operator()/migemo_get_operator(). see: rxgen.h */ 38 public enum MIGEMO_OPINDEX_OR = 0; 39 public enum MIGEMO_OPINDEX_NEST_IN = 1; 40 public enum MIGEMO_OPINDEX_NEST_OUT = 2; 41 public enum MIGEMO_OPINDEX_SELECT_IN = 3; 42 public enum MIGEMO_OPINDEX_SELECT_OUT = 4; 43 public enum MIGEMO_OPINDEX_NEWLINE = 5; 44 45 /* see: rxgen.h */ 46 public alias MIGEMO_PROC_CHAR2INT = extern (C) nothrow @nogc int function(const (char)*, uint*); 47 public alias MIGEMO_PROC_INT2CHAR = extern (C) nothrow @nogc int function(uint, char*); 48 49 enum DICT_MIGEMO = "migemo-dict"; 50 enum DICT_ROMA2HIRA = "roma2hira.dat"; 51 enum DICT_HIRA2KATA = "hira2kata.dat"; 52 enum DICT_HAN2ZEN = "han2zen.dat"; 53 enum DICT_ZEN2HAN = "zen2han.dat"; 54 enum BUFLEN_DETECT_CHARSET = 4096; 55 56 alias MIGEMO_PROC_ADDWORD = extern (C) nothrow @nogc int function(void* data, char* word); 57 58 /** 59 * migemoオブジェクト 60 */ 61 struct _migemo 62 { 63 int enable; 64 migemo_d.mnode.mtree_p mtree; 65 int charset; 66 migemo_d.romaji.romaji* roma2hira; 67 migemo_d.romaji.romaji* hira2kata; 68 migemo_d.romaji.romaji* han2zen; 69 migemo_d.romaji.romaji* zen2han; 70 migemo_d.rxgen.rxgen* rx; 71 .MIGEMO_PROC_ADDWORD addword; 72 migemo_d.charset.CHARSET_PROC_CHAR2INT char2int; 73 } 74 75 /** 76 * Migemoオブジェクト。migemo_open()で作成され、migemo_closeで破棄される。 77 */ 78 public alias migemo = ._migemo; 79 80 static immutable char[] VOWEL_CHARS = "aiueo\0"; 81 82 pure nothrow @nogc 83 private int my_strlen(const (char)* s) 84 85 in 86 { 87 assert(s != null); 88 } 89 90 do 91 { 92 size_t len = core.stdc..string.strlen(s); 93 94 return (len <= int.max) ? (cast(int)(len)) : (int.max); 95 } 96 97 nothrow @nogc 98 package migemo_d.mnode.mtree_p load_mtree_dictionary(migemo_d.mnode.mtree_p mtree, const (char)* dict_file) 99 100 in 101 { 102 assert(mtree != null); 103 assert(dict_file != null); 104 } 105 106 do 107 { 108 core.stdc.stdio.FILE* fp = core.stdc.stdio.fopen(dict_file, "rt"); 109 110 if (fp == null) { 111 /* Can't find file */ 112 return null; 113 } 114 115 scope (exit) { 116 if (fp != null) { 117 core.stdc.stdio.fclose(fp); 118 fp = null; 119 } 120 } 121 122 mtree = migemo_d.mnode.mnode_load(mtree, fp); 123 124 return mtree; 125 } 126 127 nothrow @nogc 128 package migemo_d.mnode.mtree_p load_mtree_dictionary2(.migemo* obj, const (char)* dict_file) 129 130 in 131 { 132 assert(obj != null); 133 } 134 135 do 136 { 137 if (obj.charset == migemo_d.charset.CHARSET_NONE) { 138 /* 辞書の文字セットにあわせて正規表現生成時の関数を変更する */ 139 migemo_d.charset.CHARSET_PROC_CHAR2INT char2int = null; 140 migemo_d.charset.CHARSET_PROC_INT2CHAR int2char = null; 141 obj.charset = migemo_d.charset.charset_detect_file(dict_file); 142 migemo_d.charset.charset_getproc(obj.charset, &char2int, &int2char); 143 144 if (char2int != null) { 145 .migemo_setproc_char2int(obj, cast(.MIGEMO_PROC_CHAR2INT)(char2int)); 146 obj.char2int = char2int; 147 } 148 149 if (int2char != null) { 150 .migemo_setproc_int2char(obj, cast(.MIGEMO_PROC_INT2CHAR)(int2char)); 151 } 152 } 153 154 return .load_mtree_dictionary(obj.mtree, dict_file); 155 } 156 157 pure nothrow @nogc 158 package void dircat(char* buf, const (char)* dir, const (char)* file) 159 160 in 161 { 162 assert(buf != null); 163 assert(dir != null); 164 assert(file != null); 165 } 166 167 do 168 { 169 core.stdc..string.strcpy(buf, dir); 170 core.stdc..string.strcat(buf, "/"); 171 core.stdc..string.strcat(buf, file); 172 } 173 174 /* 175 * migemo interfaces 176 */ 177 178 /** 179 * Migemoオブジェクトに辞書、またはデータファイルを追加読み込みする。 180 * dict_fileは読み込むファイル名を指定する。dict_idは読み込む辞書・データの 181 * 種類を指定するもので以下のうちどれか一つを指定する: 182 * 183 * <dl> 184 * <dt>MIGEMO_DICTID_MIGEMO</dt> 185 * <dd>mikgemo-dict辞書</dd> 186 * <dt>MIGEMO_DICTID_ROMA2HIRA</dt> 187 * <dd>ローマ字→平仮名変換表</dd> 188 * <dt>MIGEMO_DICTID_HIRA2KATA</dt> 189 * <dd>平仮名→カタカナ変換表</dd> 190 * <dt>MIGEMO_DICTID_HAN2ZEN</dt> 191 * <dd>半角→全角変換表</dd> 192 * <dt>MIGEMO_DICTID_ZEN2HAN</dt> 193 * <dd>全角→半角変換表</dd> 194 * </dl> 195 * 196 * 戻り値は実際に読み込んだ種類を示し、上記の他に読み込みに失敗したことを示す 197 * 次の価が返ることがある。 198 * 199 * <dl><dt>MIGEMO_DICTID_INVALID</dt></dl> 200 * 201 * Params: 202 * obj = Migemoオブジェクト 203 * dict_id = 辞書ファイルの種類 204 * dict_file = 辞書ファイルのパス 205 */ 206 //MIGEMO_CALLTYPE 207 extern (C) 208 nothrow @nogc 209 export int migemo_load(.migemo* obj, int dict_id, const (char)* dict_file) 210 211 do 212 { 213 if ((obj == null) && (dict_file != null)) { 214 return .MIGEMO_DICTID_INVALID; 215 } 216 217 if (dict_id == .MIGEMO_DICTID_MIGEMO) { 218 /* migemo辞書読み込み */ 219 migemo_d.mnode.mtree_p mtree = .load_mtree_dictionary2(obj, dict_file); 220 221 if (mtree == null) { 222 return .MIGEMO_DICTID_INVALID; 223 } 224 225 obj.mtree = mtree; 226 obj.enable = 1; 227 228 /* Loaded successfully */ 229 return dict_id; 230 } else { 231 migemo_d.romaji.romaji* dict; 232 233 switch (dict_id) { 234 /* ローマ字辞書読み込み */ 235 case .MIGEMO_DICTID_ROMA2HIRA: 236 dict = obj.roma2hira; 237 238 break; 239 240 /* カタカナ辞書読み込み */ 241 case .MIGEMO_DICTID_HIRA2KATA: 242 dict = obj.hira2kata; 243 244 break; 245 246 /* 半角→全角辞書読み込み */ 247 case .MIGEMO_DICTID_HAN2ZEN: 248 dict = obj.han2zen; 249 250 break; 251 252 /* 半角→全角辞書読み込み */ 253 case .MIGEMO_DICTID_ZEN2HAN: 254 dict = obj.zen2han; 255 256 break; 257 258 default: 259 dict = null; 260 261 break; 262 } 263 264 if ((dict != null) && (migemo_d.romaji.romaji_load(dict, dict_file) == 0)) { 265 return dict_id; 266 } else { 267 return .MIGEMO_DICTID_INVALID; 268 } 269 } 270 } 271 272 /** 273 * Migemoオブジェクトを作成する。作成に成功するとオブジェクトが戻り値として 274 * 返り、失敗するとNULLが返る。dictで指定したファイルがmigemo-dict辞書として 275 * オブジェクト作成時に読み込まれる。辞書と同じディレクトリに: 276 * 277 * <dl> 278 * <dt>roma2hira.dat</dt> 279 * <dd>ローマ字→平仮名変換表 </dd> 280 * <dt>hira2kata.dat</dt> 281 * <dd>平仮名→カタカナ変換表 </dd> 282 * <dt>han2zen.dat</dt> 283 * <dd>半角→全角変換表 </dd> 284 * </dl> 285 * 286 * という名前のファイルが存在すれば、存在したものだけが読み込まれる。dictに 287 * NULLを指定した場合には、辞書を含めていかなるファイルも読み込まれない。 288 * ファイルはオブジェクト作成後にもmigemo_load()関数を使用することで追加読み 289 * 込みができる。 290 * 291 * Params: 292 * dict = migemo-dict辞書のパス。NULLの時は辞書を読み込まない。 293 * 294 * Returns: 作成されたMigemoオブジェクト 295 */ 296 //MIGEMO_CALLTYPE 297 extern (C) 298 nothrow @nogc 299 export .migemo* migemo_open(const (char)* dict) 300 301 do 302 { 303 /* migemoオブジェクトと各メンバを構築 */ 304 .migemo* obj = cast(.migemo*)(core.memory.pureCalloc(1, .migemo.sizeof)); 305 306 if (obj == null) { 307 return null; 308 } 309 310 obj.enable = 0; 311 obj.mtree = migemo_d.mnode.mnode_open(null); 312 obj.charset = migemo_d.charset.CHARSET_NONE; 313 obj.rx = migemo_d.rxgen.rxgen_open(); 314 obj.roma2hira = migemo_d.romaji.romaji_open(); 315 obj.hira2kata = migemo_d.romaji.romaji_open(); 316 obj.han2zen = migemo_d.romaji.romaji_open(); 317 obj.zen2han = migemo_d.romaji.romaji_open(); 318 319 if ((obj.rx == null) || (obj.roma2hira == null) || (obj.hira2kata == null) || (obj.han2zen == null) || (obj.zen2han == null)) { 320 .migemo_close(obj); 321 322 return obj = null; 323 } 324 325 /* デフォルトmigemo辞書が指定されていたらローマ字とカタカナ辞書も探す */ 326 if (dict != null) { 327 /** 328 * いい加減な数値 329 */ 330 enum _MAX_PATH = 1024; 331 332 char[_MAX_PATH] dir; 333 char[_MAX_PATH] roma_dict; 334 char[_MAX_PATH] kata_dict; 335 char[_MAX_PATH] h2z_dict; 336 char[_MAX_PATH] z2h_dict; 337 338 migemo_d.filename.filename_directory(&(dir[0]), dict); 339 const (char)* tmp = (core.stdc..string.strlen(&(dir[0]))) ? (&(dir[0])) : ("."); 340 .dircat(&(roma_dict[0]), tmp, .DICT_ROMA2HIRA); 341 .dircat(&(kata_dict[0]), tmp, .DICT_HIRA2KATA); 342 .dircat(&(h2z_dict[0]), tmp, .DICT_HAN2ZEN); 343 .dircat(&(z2h_dict[0]), tmp, .DICT_ZEN2HAN); 344 345 migemo_d.mnode.mtree_p mtree = .load_mtree_dictionary2(obj, dict); 346 347 if (mtree != null) { 348 obj.mtree = mtree; 349 obj.enable = 1; 350 migemo_d.romaji.romaji_load(obj.roma2hira, &(roma_dict[0])); 351 migemo_d.romaji.romaji_load(obj.hira2kata, &(kata_dict[0])); 352 migemo_d.romaji.romaji_load(obj.han2zen, &(h2z_dict[0])); 353 migemo_d.romaji.romaji_load(obj.zen2han, &(z2h_dict[0])); 354 } 355 } 356 357 return obj; 358 } 359 360 /** 361 * Migemoオブジェクトを破棄し、使用していたリソースを解放する。 362 * 363 * Params: 364 * obj = 破棄するMigemoオブジェクト 365 */ 366 //MIGEMO_CALLTYPE 367 extern (C) 368 nothrow @nogc 369 export void migemo_close(.migemo* obj) 370 371 do 372 { 373 if (obj != null) { 374 if (obj.zen2han != null) { 375 migemo_d.romaji.romaji_close(obj.zen2han); 376 obj.zen2han = null; 377 } 378 379 if (obj.han2zen != null) { 380 migemo_d.romaji.romaji_close(obj.han2zen); 381 obj.han2zen = null; 382 } 383 384 if (obj.hira2kata != null) { 385 migemo_d.romaji.romaji_close(obj.hira2kata); 386 obj.hira2kata = null; 387 } 388 389 if (obj.roma2hira != null) { 390 migemo_d.romaji.romaji_close(obj.roma2hira); 391 obj.roma2hira = null; 392 } 393 394 if (obj.rx != null) { 395 migemo_d.rxgen.rxgen_close(obj.rx); 396 obj.rx = null; 397 } 398 399 if (obj.mtree != null) { 400 migemo_d.mnode.mnode_close(obj.mtree); 401 obj.mtree = null; 402 } 403 404 core.memory.pureFree(obj); 405 obj = null; 406 } 407 } 408 409 /* 410 * query version 2 411 */ 412 413 /** 414 * mnodeの持つ単語リストを正規表現生成エンジンに入力する。 415 */ 416 extern (C) 417 nothrow @nogc 418 package void migemo_query_proc(migemo_d.mnode.mnode* p, void* data) 419 420 in 421 { 422 assert(p != null); 423 assert(data != null); 424 } 425 426 do 427 { 428 .migemo* object = cast(.migemo*)(data); 429 430 for (migemo_d.wordlist.wordlist_p list = p.list; list != null; list = list.next) { 431 object.addword(object, list.ptr_); 432 } 433 } 434 435 /** 436 * バッファを用意してmnodeに再帰で書き込ませる 437 */ 438 nothrow @nogc 439 package void add_mnode_query(.migemo* object, char* query) 440 441 do 442 { 443 migemo_d.mnode.mnode* pnode = migemo_d.mnode.mnode_query(object.mtree, query); 444 445 if (pnode != null) { 446 migemo_d.mnode.mnode_traverse(pnode, &.migemo_query_proc, object); 447 } 448 } 449 450 /** 451 * 入力をローマから仮名に変換して検索キーに加える。 452 */ 453 nothrow @nogc 454 package int add_roma(.migemo* object, char* query) 455 456 in 457 { 458 assert(object != null); 459 } 460 461 do 462 { 463 char* stop; 464 char* hira = migemo_d.romaji.romaji_convert(object.roma2hira, query, &stop); 465 466 scope (exit) { 467 if (hira != null) { 468 /* 平仮名解放 */ 469 migemo_d.romaji.romaji_release(object.roma2hira, hira); 470 hira = null; 471 } 472 } 473 474 if (stop == null) { 475 object.addword(object, hira); 476 /* 平仮名による辞書引き */ 477 .add_mnode_query(object, hira); 478 479 /* 片仮名文字列を生成し候補に加える */ 480 char* kata = migemo_d.romaji.romaji_convert2(object.hira2kata, hira, null, 0); 481 482 scope (exit) { 483 if (kata != null) { 484 /* カタカナ解放 */ 485 migemo_d.romaji.romaji_release(object.hira2kata, kata); 486 kata = null; 487 } 488 } 489 490 object.addword(object, kata); 491 492 /* TODO: 半角カナを生成し候補に加える */ 493 version (all) { 494 char* han = migemo_d.romaji.romaji_convert2(object.zen2han, kata, null, 0); 495 496 scope (exit) { 497 if (han != null) { 498 migemo_d.romaji.romaji_release(object.zen2han, han); 499 han = null; 500 } 501 } 502 503 object.addword(object, han); 504 /*core.stdc.stdio.printf("kata=%s\nhan=%s\n", kata, han);*/ 505 } 506 507 /* カタカナによる辞書引き */ 508 .add_mnode_query(object, kata); 509 } 510 511 return (stop) ? (1) : (0); 512 } 513 514 /** 515 * ローマ字の末尾に母音を付け加えて、各々を検索キーに加える。 516 */ 517 nothrow @nogc 518 package void add_dubious_vowels(.migemo* object, char* buf, size_t index) 519 520 in 521 { 522 assert(buf != null); 523 } 524 525 do 526 { 527 for (immutable (char)* ptr_ = &(.VOWEL_CHARS[0]); *ptr_ != '\0'; ++ptr_) { 528 buf[index] = *ptr_; 529 .add_roma(object, buf); 530 } 531 } 532 533 /** 534 * ローマ字変換が不完全だった時に、[aiueo]および"xn"と"xtu"を補って変換して 535 * みる。 536 */ 537 nothrow @nogc 538 package void add_dubious_roma(.migemo* object, migemo_d.rxgen.rxgen* rx, char* query) 539 540 in 541 { 542 assert(query != null); 543 } 544 545 do 546 { 547 size_t len = core.stdc..string.strlen(query); 548 549 /* 550 * ローマ字の末尾のアレンジのためのバッファを確保する。 551 * 内訳: オリジナルの長さ、NUL、吃音(xtu)、補足母音([aieuo]) 552 */ 553 enum size_t end_buf_len = 1 + 3 + 1; 554 555 if (len == 0) { 556 return; 557 } 558 559 if (len > (size_t.max - end_buf_len)) { 560 return; 561 } 562 563 size_t max = len + end_buf_len; 564 char* buf = cast(char*)(core.memory.pureMalloc(max)); 565 566 if (buf == null) { 567 return; 568 } 569 570 scope (exit) { 571 if (buf != null) { 572 core.memory.pureFree(buf); 573 buf = null; 574 } 575 } 576 577 buf[0 .. len] = query[0 .. len]; 578 core.stdc..string.memset(&buf[len], 0, max - len); 579 580 if (core.stdc..string.strchr(&(.VOWEL_CHARS[0]), buf[len - 1]) == null) { 581 .add_dubious_vowels(object, buf, len); 582 583 /* 未確定単語の長さが2未満か、未確定文字の直前が母音ならば… */ 584 if ((len < 2) || (core.stdc..string.strchr(&(.VOWEL_CHARS[0]), buf[len - 2]) != null)) { 585 if (buf[len - 1] == 'n') { 586 /* 「ん」を補ってみる */ 587 buf[len - 1] = 'x'; 588 buf[len] = 'n'; 589 .add_roma(object, buf); 590 } else { 591 /* 「っ{元の子音}{母音}」を補ってみる */ 592 buf[len + 2] = buf[len - 1]; 593 buf[len - 1] = 'x'; 594 buf[len] = 't'; 595 buf[len + 1] = 'u'; 596 .add_dubious_vowels(object, buf, len + 3); 597 } 598 } 599 } 600 } 601 602 /** 603 * queryを文節に分解する。文節の切れ目は通常アルファベットの大文字。文節が複 604 * 数文字の大文字で始まった文節は非大文字を区切りとする。 605 */ 606 nothrow @nogc 607 package migemo_d.wordlist.wordlist_p parse_query(.migemo* object, const (char)* query) 608 609 in 610 { 611 assert(object != null); 612 assert(query != null); 613 } 614 615 do 616 { 617 const (char)* curr = query; 618 migemo_d.wordlist.wordlist_p querylist = null; 619 migemo_d.wordlist.wordlist_p* pp = &querylist; 620 621 int len; 622 623 while (true) { 624 int sum = 0; 625 626 if ((object.char2int == null) || ((len = object.char2int(curr, null)) < 1)) { 627 len = 1; 628 } 629 630 const (char)* start = curr; 631 int upper = ((len == 1) && (core.stdc.ctype.isupper(*curr)) && (core.stdc.ctype.isupper(curr[1]))); 632 curr += len; 633 sum += len; 634 635 while (true) { 636 if ((object.char2int == null) || ((len = object.char2int(curr, null)) < 1)) { 637 len = 1; 638 } 639 640 if ((*curr == '\0') || ((len == 1) && ((core.stdc.ctype.isupper(*curr) != 0) != upper))) { 641 break; 642 } 643 644 curr += len; 645 sum += len; 646 } 647 648 /* 文節を登録する */ 649 if ((start != null) && (start < curr)) { 650 *pp = migemo_d.wordlist.wordlist_open_len(start, sum); 651 pp = &(*pp).next; 652 } 653 654 if (*curr == '\0') { 655 break; 656 } 657 } 658 659 return querylist; 660 } 661 662 /** 663 * 1つの単語をmigemo変換。引数のチェックは行なわない。 664 */ 665 nothrow @nogc 666 package int query_a_word(.migemo* object, char* query) 667 668 in 669 { 670 assert(object != null); 671 assert(query != null); 672 } 673 674 do 675 { 676 size_t len = core.stdc..string.strlen(query); 677 678 assert(size_t.max > len); 679 680 /* query自信はもちろん候補に加える */ 681 object.addword(object, query); 682 683 /* queryそのものでの辞書引き */ 684 char* lower = cast(char*)(core.memory.pureMalloc(len + 1)); 685 686 scope (exit) { 687 if (lower != null) { 688 core.memory.pureFree(lower); 689 lower = null; 690 } 691 } 692 693 if (lower == null) { 694 .add_mnode_query(object, query); 695 } else { 696 int i = 0; 697 int step; 698 699 // MBを考慮した大文字→小文字変換 700 while (i <= len) { 701 if ((object.char2int == null) || ((step = object.char2int(&query[i], null)) < 1)) { 702 step = 1; 703 } 704 705 if ((step == 1) && (core.stdc.ctype.isupper(query[i]))) { 706 lower[i] = cast(char)(core.stdc.ctype.tolower(query[i])); 707 } else { 708 core.stdc..string.memcpy(&lower[i], &query[i], step); 709 } 710 711 i += step; 712 } 713 714 .add_mnode_query(object, lower); 715 } 716 717 /* queryを全角にして候補に加える */ 718 char* zen = migemo_d.romaji.romaji_convert2(object.han2zen, query, null, 0); 719 720 scope (exit) { 721 if (zen != null) { 722 migemo_d.romaji.romaji_release(object.han2zen, zen); 723 zen = null; 724 } 725 } 726 727 if (zen != null) { 728 object.addword(object, zen); 729 } 730 731 /* queryを半角にして候補に加える */ 732 char* han = migemo_d.romaji.romaji_convert2(object.zen2han, query, null, 0); 733 734 scope (exit) { 735 if (han != null) { 736 migemo_d.romaji.romaji_release(object.zen2han, han); 737 han = null; 738 } 739 } 740 741 if (han != null) { 742 object.addword(object, han); 743 } 744 745 /* 平仮名、カタカナ、及びそれによる辞書引き追加 */ 746 if (.add_roma(object, query)) { 747 .add_dubious_roma(object, object.rx, query); 748 } 749 750 return 1; 751 } 752 753 extern (C) 754 nothrow @nogc 755 package int addword_rxgen(void* object, char* word) 756 757 in 758 { 759 assert(object != null); 760 } 761 762 do 763 { 764 /* 正規表現生成エンジンに追加された単語を表示する */ 765 /*core.stdc.stdio.printf("addword_rxgen: %s\n", word);*/ 766 return migemo_d.rxgen.rxgen_add((cast(.migemo*)(object)).rx, word); 767 } 768 769 /** 770 * queryで与えられた文字列(ローマ字)を日本語検索のための正規表現へ変換する。 771 * 戻り値は変換された結果の文字列(正規表現)で、使用後は#migemo_release()関数 772 * へ渡すことで解放しなければならない。 773 * 774 * Params: 775 * object = Migemoオブジェクト 776 * query = 問い合わせ文字列 777 * 778 * Returns: 正規表現文字列。#migemo_release() で解放する必要有り。 779 */ 780 //MIGEMO_CALLTYPE 781 extern (C) 782 nothrow @nogc 783 export char* migemo_query(.migemo* object, const (char)* query) 784 785 do 786 { 787 char* retval = null; 788 789 if ((object != null) && (object.rx != null) && (query != null)) { 790 migemo_d.wordlist.wordlist_p querylist = .parse_query(object, query); 791 792 scope (exit) { 793 if (querylist != null) { 794 migemo_d.wordlist.wordlist_close(querylist); 795 querylist = null; 796 } 797 } 798 799 if (querylist == null) { 800 /* 空queryのためエラー */ 801 return retval; 802 } 803 804 migemo_d.wordbuf.wordbuf_p outbuf = migemo_d.wordbuf.wordbuf_open(); 805 806 scope (exit) { 807 if (outbuf != null) { 808 retval = outbuf.buf; 809 outbuf.buf = null; 810 migemo_d.wordbuf.wordbuf_close(outbuf); 811 outbuf = null; 812 } 813 } 814 815 if (outbuf == null) { 816 /* 出力用のメモリ領域不足のためエラー */ 817 return retval; 818 } 819 820 /* 単語群をrxgenオブジェクトに入力し正規表現を得る */ 821 object.addword = &.addword_rxgen; 822 migemo_d.rxgen.rxgen_reset(object.rx); 823 824 for (migemo_d.wordlist.wordlist_p p = querylist; p != null; p = p.next) { 825 /*core.stdc.stdio.printf("query=%s\n", p.ptr_);*/ 826 .query_a_word(object, p.ptr_); 827 828 /* 検索パターン(正規表現)生成 */ 829 char* answer = migemo_d.rxgen.rxgen_generate(object.rx); 830 831 scope (exit) { 832 if (answer != null) { 833 migemo_d.rxgen.rxgen_release(object.rx, answer); 834 answer = null; 835 } 836 } 837 838 migemo_d.rxgen.rxgen_reset(object.rx); 839 migemo_d.wordbuf.wordbuf_cat(outbuf, answer); 840 } 841 } 842 843 return retval; 844 } 845 846 /** 847 * 使い終わったmigemo_query()関数で得られた正規表現を解放する。 848 * 849 * Params: 850 * p = Migemoオブジェクト 851 * string = 正規表現文字列 852 */ 853 //MIGEMO_CALLTYPE 854 extern (C) 855 pure nothrow @trusted @nogc 856 export void migemo_release(.migemo* p, char* string_) 857 858 do 859 { 860 if (string_ != null) { 861 core.memory.pureFree(string_); 862 } 863 } 864 865 /** 866 * Migemoオブジェクトが生成する正規表現に使用するメタ文字(演算子)を指定す 867 * る。indexでどのメタ文字かを指定し、opで置き換える。indexには以下の値が指 868 * 定可能である: 869 * 870 * <dl> 871 * <dt>MIGEMO_OPINDEX_OR</dt> 872 * <dd>論理和。デフォルトは "|" 。vimで利用する際は "\|" 。</dd> 873 * <dt>MIGEMO_OPINDEX_NEST_IN</dt> 874 * <dd>グルーピングに用いる開き括弧。デフォルトは "(" 。vimではレジスタ 875 * \\1〜\\9に記憶させないようにするために "\%(" を用いる。Perlでも同様の 876 * ことを目論むならば "(?:" が使用可能。</dd> 877 * <dt>MIGEMO_OPINDEX_NEST_OUT</dt> 878 * <dd>グルーピングの終了を表す閉じ括弧。デフォルトでは ")" 。vimでは 879 * "\)" 。</dd> 880 * <dt>MIGEMO_OPINDEX_SELECT_IN</dt> 881 * <dd>選択の開始を表す開き角括弧。デフォルトでは "[" 。</dd> 882 * <dt>MIGEMO_OPINDEX_SELECT_OUT</dt> 883 * <dd>選択の終了を表す閉じ角括弧。デフォルトでは "]" 。</dd> 884 * <dt>MIGEMO_OPINDEX_NEWLINE</dt> 885 * <dd>各文字の間に挿入される「0個以上の空白もしくは改行にマッチする」 886 * パターン。デフォルトでは "" であり設定されない。vimでは "\_s*" を指 887 * 定する。</dd> 888 * </dl> 889 * 890 * デフォルトのメタ文字は特に断りがない限りPerlのそれと同じ意味である。設定 891 * に成功すると戻り値は1(0以外)となり、失敗すると0になる。 892 * 893 * Params: 894 * object = Migemoオブジェクト 895 * index = メタ文字識別子 896 * op = メタ文字文字列 897 * 898 * Returns: 成功時0以外、失敗時0。 899 */ 900 //MIGEMO_CALLTYPE 901 extern (C) 902 pure nothrow @nogc 903 export int migemo_set_operator(.migemo* object, int index, const (char)* op) 904 905 do 906 { 907 if (object != null) { 908 int retval = migemo_d.rxgen.rxgen_set_operator(object.rx, index, op); 909 910 return (retval) ? (0) : (1); 911 } else { 912 return 0; 913 } 914 } 915 916 /** 917 * Migemoオブジェクトが生成する正規表現に使用しているメタ文字(演算子)を取得 918 * する。indexについてはmigemo_set_operator()関数を参照。戻り値にはindexの指 919 * 定が正しければメタ文字を格納した文字列へのポインタが、不正であればNULLが 920 * 返る。 921 * 922 * Params: 923 * object = Migemoオブジェクト 924 * index = メタ文字識別子 925 * 926 * Returns: 現在のメタ文字文字列 927 */ 928 //MIGEMO_CALLTYPE 929 extern (C) 930 pure nothrow @trusted @nogc @live 931 export const (char)* migemo_get_operator(.migemo* object, int index) 932 933 do 934 { 935 return (object != null) ? (migemo_d.rxgen.rxgen_get_operator(object.rx, index)) : (null); 936 } 937 938 /** 939 * Migemoオブジェクトにコード変換用のプロシージャを設定する。プロシージャに 940 * ついての詳細は「型リファレンス」セクションのMIGEMO_PROC_CHAR2INTを参照。 941 * 942 * Params: 943 * object = Migemoオブジェクト 944 * proc = コード変換用プロシージャ 945 */ 946 //MIGEMO_CALLTYPE 947 extern (C) 948 nothrow @nogc 949 export void migemo_setproc_char2int(.migemo* object, .MIGEMO_PROC_CHAR2INT proc) 950 951 do 952 { 953 if (object != null) { 954 migemo_d.rxgen.rxgen_setproc_char2int(object.rx, proc); 955 } 956 } 957 958 /** 959 * Migemoオブジェクトにコード変換用のプロシージャを設定する。プロシージャに 960 * ついての詳細は「型リファレンス」セクションのMIGEMO_PROC_INT2CHARを参照。 961 * 962 * Params: 963 * object = Migemoオブジェクト 964 * proc = コード変換用プロシージャ 965 */ 966 //MIGEMO_CALLTYPE 967 extern (C) 968 nothrow @nogc 969 export void migemo_setproc_int2char(.migemo* object, .MIGEMO_PROC_INT2CHAR proc) 970 971 do 972 { 973 if (object != null) { 974 migemo_d.rxgen.rxgen_setproc_int2char(object.rx, proc); 975 } 976 } 977 978 /** 979 * Migemoオブジェクトにmigemo_dictが読み込めているかをチェックする。有効な 980 * migemo_dictを読み込めて内部に変換テーブルが構築できていれば0以外(TRUE) 981 * を、構築できていないときには0(FALSE)を返す。 982 * 983 * Params: 984 * obj = Migemoオブジェクト 985 * 986 * Returns: 成功時0以外、失敗時0。 987 */ 988 //MIGEMO_CALLTYPE 989 extern (C) 990 pure nothrow @trusted @nogc @live 991 export int migemo_is_enable(.migemo* obj) 992 993 do 994 { 995 return (obj != null) ? (obj.enable) : (0); 996 } 997 998 debug { 999 /* 1000 * 主にデバッグ用の隠し関数 1001 */ 1002 //MIGEMO_CALLTYPE 1003 extern (C) 1004 nothrow @nogc 1005 export void migemo_print(.migemo* object) 1006 1007 do 1008 { 1009 if (object != null) { 1010 migemo_d.mnode.mnode_print(object.mtree, null); 1011 } 1012 } 1013 }