Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / src / slm / mmseg / mmseg.cpp
1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3  *
4  * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * The contents of this file are subject to the terms of either the GNU Lesser
7  * General Public License Version 2.1 only ("LGPL") or the Common Development and
8  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
9  * file except in compliance with the License. You can obtain a copy of the CDDL at
10  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
11  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
12  * specific language governing permissions and limitations under the License. When
13  * distributing the software, include this License Header Notice in each file and
14  * include the full text of the License in the License file as well as the
15  * following notice:
16  *
17  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
18  * (CDDL)
19  * For Covered Software in this distribution, this License shall be governed by the
20  * laws of the State of California (excluding conflict-of-law provisions).
21  * Any litigation relating to this License shall be subject to the jurisdiction of
22  * the Federal Courts of the Northern District of California and the state courts
23  * of the State of California, with venue lying in Santa Clara County, California.
24  *
25  * Contributor(s):
26  *
27  * If you wish your version of this file to be governed by only the CDDL or only
28  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
29  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
30  * license." If you don't indicate a single choice of license, a recipient has the
31  * option to distribute your version of this file under either the CDDL or the LGPL
32  * Version 2.1, or to extend the choice of license to its licensees as provided
33  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
34  * Version 2 license, then the option applies only if the new code is made subject
35  * to such option by the copyright holder.
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #ifdef HAVE_ASSERT_H
43 #include <assert.h>
44 #endif
45
46 #ifdef HAVE_GETOPT_H
47 #include <getopt.h>
48 #endif
49
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <locale.h>
53
54 #include "../sim_dict.h"
55 #include "../sim_sen.h"
56
57 static struct option long_options[] =
58 {
59     { "dict", 1, 0, 'd' },
60     { "format", 1, 0, 'f' },
61     { "show-id", 0, 0, 'i' },
62     { "s-tok", 1, 0, 's' },
63     { "ambiguious-id", 1, 0, 'a' },
64     { 0, 0, 0, 0 }
65 };
66
67 static char* s_strDictFile = NULL;
68 static bool s_bTextOut = false;
69 static bool s_bShowId = false;
70 static TSIMWordId s_iSTOKID = 10;
71 static TSIMWordId s_iAmbiID = 0;
72
73 static CSIMDict *s_dict = NULL;
74
75 static void
76 ShowUsage()
77 {
78     fprintf(stderr, "\nUsage:\n");
79     fprintf(
80         stderr,
81         "mmseg -d dict_file [-f (text|bin)] [-i] [-s STOK_ID] [-a AMBI_ID]\n\n");
82     fprintf(stderr, "  -f --format:\n");
83     fprintf(stderr,
84             "    Output Format, can be 'text' or 'bin'. default 'bin'\n");
85     fprintf(
86         stderr,
87         "    Normally, in text mode, word text are output, while in binary mode,\n");
88     fprintf(stderr,
89             "    binary short integer of the word-ids are written to stdout.\n");
90     fprintf(stderr, "  -s --stok:\n");
91     fprintf(stderr, "    Sentence token id. Default 10.\n");
92     fprintf(
93         stderr,
94         "    It will be written to output in binary mode after every sentence.\n");
95     fprintf(stderr, "  -i --show-id:\n");
96     fprintf(
97         stderr,
98         "    Show Id info. Under text output format mode, attach id after known.\n");
99     fprintf(stderr, "    words. If under binary mode, print id(s) in text.\n");
100     fprintf(stderr, "  -a --ambiguious-id:\n");
101     fprintf(
102         stderr,
103         "    Ambiguious means ABC => A BC or AB C. If specified (AMBI-ID != 0), \n");
104     fprintf(
105         stderr,
106         "    The sequence ABC will not be segmented, in binary mode, the AMBI-ID \n");
107     fprintf(
108         stderr,
109         "    is written out; in text mode, <ambi>ABC</ambi> will be output. Default \n");
110     fprintf(stderr, "    is 0.\n");
111     fprintf(stderr, "\n");
112     fprintf(stderr, "Notes:\n");
113     fprintf(stderr,
114             "  Under binary mode, consecutive id of 0 are merged into one 0.\n");
115     fprintf(
116         stderr,
117         "  Under text mode, no space are inserted between unknown-words. \n");
118     fprintf(stderr, "\n");
119     fprintf(stderr, "\n");
120     exit(1000);
121 }
122
123 static void
124 getParameters(int argc, char* argv[])
125 {
126     int c;
127     while ((c =
128                 getopt_long(argc, argv, "d:if:s:a:", long_options,
129                             NULL)) != -1) {
130         switch (c) {
131         case 'd':
132             s_strDictFile = strdup(optarg);
133             break;
134         case 'i':
135             s_bShowId = true;
136             break;
137         case 'f':
138             s_bTextOut = (strcmp(optarg, "text") == 0);
139             break;
140         case 's':
141             s_iSTOKID = atoi(optarg);
142             break;
143         case 'a':
144             s_iAmbiID = atoi(optarg);
145             break;
146         default:
147             ShowUsage();
148             break;
149         }
150     }
151     if (s_strDictFile == NULL)
152         ShowUsage();
153 }
154
155 static void
156 output_stok(int& nWords)
157 {
158     if (s_bShowId) {
159         if (nWords > 0)
160             printf(" ");
161         printf("%d", unsigned(s_iSTOKID));
162     } else {
163         fwrite(&s_iSTOKID, sizeof(TSIMWordId), 1, stdout);
164     }
165     ++nWords;
166 }
167
168 static void
169 output(int len,
170        const TWCHAR* p,
171        TSIMWordId idprev,
172        TSIMWordId idcur,
173        int& nWords)
174 {
175     static char mbword[1024];
176     static TWCHAR wcword[1024];
177
178     bool bRealGap = (idcur != SIM_ID_NOT_WORD || idprev != SIM_ID_NOT_WORD);
179     if (s_bTextOut) {
180         for (int i = 0; i < len; ++i, ++p)
181             wcword[i] = *p;
182         wcword[len] = 0;
183         WCSTOMBS(mbword, wcword, sizeof(mbword));
184         if (bRealGap && idprev == SIM_ID_NOT_WORD)
185             printf("(%d)", unsigned(idprev));
186         if (bRealGap && (nWords > 0))
187             printf(" ");
188         (s_iAmbiID && idcur == s_iAmbiID) ? printf("<ambi>%s</ambi>", mbword) :
189         printf("%s", mbword);
190         if (s_bShowId && idcur != SIM_ID_NOT_WORD)
191             printf("(%d)", unsigned(idcur));
192     } else {
193         if (bRealGap) {
194             if (s_bShowId) {
195                 if (nWords > 0)
196                     printf(" ");
197                 printf("%d", unsigned(idcur));
198             } else
199                 fwrite(&idcur, sizeof(TSIMWordId), 1, stdout);
200         }
201     }
202     if (bRealGap)
203         ++nWords;
204 }
205
206 /**
207  * Return 最大交集歧义长度. For example, ABCDEF if ABC CD DEF are words.
208  * if return len > word_len, then ambiguious exists at word [p p+len)...
209  */
210 int
211 getAmbiLen(const TWCHAR* p, int word_len)
212 {
213     const CSIMDict::TState* pstate;
214
215     for (int i = 1; i < word_len && *(p + i) != WCH_NULL; ++i) {
216         int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p + i);
217         if (word_len < i + len)
218             word_len = i + len;
219     }
220
221     return word_len;
222 }
223
224 static bool
225 processSingleFile(FILE* fp, int &nWords, int &nAmbis)
226 {
227     nWords = 0;
228     nAmbis = 0;
229
230     wstring sntnc;
231     CSIMCharReader *pReader = new CSIMCharReader(fp);
232     CSIMCharReader::iterator iter = pReader->begin();
233     TSIMWordId idcur, idprev = s_iSTOKID;
234
235     if (!s_bTextOut)
236         output_stok(nWords);
237
238     while (true) {
239         if (ReadSentence(sntnc, iter, false) == false)
240             break;
241
242         for (const TWCHAR *p = sntnc.c_str(); (*p); ) {
243             const CSIMDict::TState* pstate;
244             int len = s_dict->matchLongest(s_dict->getRoot(), pstate, p);
245             if (len <= 0) {
246                 idcur = SIM_ID_NOT_WORD;
247                 len = 1;
248             } else
249                 idcur = pstate->word_id;
250
251             if (s_iAmbiID != WCH_NULL) {
252                 int ambiLen = getAmbiLen(p, len);
253                 if (ambiLen > len) {
254                     len = ambiLen;
255                     idcur = s_iAmbiID;
256                     ++nAmbis;
257                 }
258             }
259
260             output(len, p, idprev, idcur, nWords);
261
262             idprev = idcur;
263             p += len;
264         }
265
266         if (!s_bTextOut) {
267             output_stok(nWords);
268             idprev = s_iSTOKID;
269         }
270     }
271
272     fflush(stdout);
273     return true;
274 }
275
276 int
277 main(int argc, char *argv[])
278 {
279     int nWords, nAmbis;
280
281     setlocale(LC_ALL, "");
282     getParameters(argc, argv);
283     argc -= optind;
284     argv += optind;
285
286     fprintf(stderr, "Loading lexicon..."); fflush(stderr);
287     s_dict = new CSIMDict();
288     if (!s_dict->parseText(s_strDictFile)) {
289         fprintf(stderr, "fail\n"); fflush(stderr);
290         exit(1001);
291     }
292     fprintf(stderr, "done"); fflush(stderr);
293
294     if (argc == 0) {
295         fprintf(stderr, "\nProcessing from stdin..."); fflush(stderr);
296         processSingleFile(stdin, nWords, nAmbis);
297         fprintf(stderr, "%d words, %d ambiguious. Done!\n", nWords, nAmbis);
298         fflush(stderr);
299     } else {
300         for (int i = 0; i < argc; ++i) {
301             fprintf(stderr, "\nProcessing %s...", argv[i]); fflush(stderr);
302             FILE *fp = fopen(argv[i], "r");
303             if (fp != NULL) {
304                 processSingleFile(fp, nWords, nAmbis);
305                 fprintf(stderr,
306                         "@Offset %ld, %d words, %d ambiguious. Done!\n",
307                         ftell(fp),
308                         nWords,
309                         nAmbis); fflush(stderr);
310             } else {
311                 fprintf(stderr, "Can not Open!!!!!!!\n"); fflush(stderr);
312             }
313             fclose(fp);
314         }
315     }
316
317     s_dict->close();
318     delete s_dict;
319     s_dict = NULL;
320     return 0;
321 }