~ubuntu-branches/ubuntu/quantal/sunpinyin/quantal

« back to all changes in this revision

Viewing changes to src/lexicon/pytrie_gen.cpp

  • Committer: Package Import Robot
  • Author(s): YunQiang Su
  • Date: 2012-03-30 15:31:55 UTC
  • mfrom: (1.1.3) (1.2.7 sid)
  • Revision ID: package-import@ubuntu.com-20120330153155-qgls77sogzgtg9zp
Tags: 2.0.3+git20120222-1
* Team upload: git snapshot 20120222.
   - fix breaks if LDFLAGS in environment contains
       multiple words (Closese #646001).
   - rm patches merged to upstream:
       append-os-environ-toenv.patch
       fix-ftbfs-on-sh.patch
       remove-10-candidate-words-limitation.patch
   - refresh disable-lm-dict-compile.patch.
* Bump stardard version to 3.9.3: no modify needed.
* add libsunpinyin3-dbg and python-sunpinyin packages.
* debian/compat to 9, multiarch it.
* rewrite debian/rules with dh 7 format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
        idset.insert(id);
41
41
    else {
42
42
        const CPinyinTrieMaker::TWordId& a = *it;
43
 
        if ((a.anony.m_bHide && !id.anony.m_bHide) || (a.anony.m_bHide == id.anony.m_bHide && a.anony.m_cost > id.anony.m_cost)) {
 
43
        if ((a.anony.m_bHide &&
 
44
             !id.anony.m_bHide) ||
 
45
            (a.anony.m_bHide == id.anony.m_bHide && a.anony.m_cost >
 
46
             id.anony.m_cost)) {
44
47
            idset.erase(it);
45
48
            idset.insert(id);
46
49
        }
48
51
}
49
52
 
50
53
struct TSyllableInfo {
51
 
    std::string   m_py;
52
 
    int           m_cost;
 
54
    std::string m_py;
 
55
    int m_cost;
53
56
 
54
 
    TSyllableInfo(const char* py=NULL, int cost=0) : m_py(py), m_cost(cost) {}
55
 
    bool operator< (const TSyllableInfo& b) const { return m_py < b.m_py; }
 
57
    TSyllableInfo(const char* py = NULL, int cost = 0) : m_py(py), m_cost(cost)
 
58
    {
 
59
    }
 
60
    bool
 
61
    operator<(const TSyllableInfo& b) const
 
62
    {
 
63
        return m_py < b.m_py;
 
64
    }
56
65
};
57
66
 
58
67
#ifdef HAVE_ICONV_H
59
 
bool isCorrectConverted(const char* utf8, iconv_t ic, iconv_t ric)
 
68
bool
 
69
isCorrectConverted(const char* utf8, iconv_t ic, iconv_t ric)
60
70
{
61
71
    static char gbstr[256];
62
72
    static char utstr[256];
63
73
 
64
74
    TIConvSrcPtr src = (TIConvSrcPtr)utf8;
65
 
    size_t srclen = strlen((char*)src)+1;
66
 
    char* dst = (char *)gbstr;
 
75
    size_t srclen = strlen((char*)src) + 1;
 
76
    char* dst = (char*)gbstr;
67
77
    size_t dstlen = 256;
68
78
    size_t res = iconv(ic, &src, &srclen, &dst, &dstlen);
69
79
 
70
80
    if (res != size_t(-1) && srclen == 0) {
71
81
        // do revert convertion and compare them
72
82
        src = (TIConvSrcPtr)gbstr;
73
 
        srclen = strlen((char*)src)+1;
74
 
        dst = (char *)utstr;
 
83
        srclen = strlen((char*)src) + 1;
 
84
        dst = (char*)utstr;
75
85
        dstlen = 256;
76
86
        res = iconv(ric, &src, &srclen, &dst, &dstlen);
77
87
        if (res != size_t(-1) && srclen == 0)
78
 
            return (strcmp(utf8, utstr) == 0);
 
88
            return(strcmp(utf8, utstr) == 0);
79
89
    }
80
90
    return false;
81
91
}
82
92
 
83
93
//return: bit 0x1: contains some gbk out of gb2312, bit 0x2: contains some gb18030 outof gbk
84
 
unsigned getPureGBEncoding(const char* utf8str)
 
94
unsigned
 
95
getPureGBEncoding(const char* utf8str)
85
96
{
86
97
    static iconv_t ic_gb = iconv_open("GB2312", "UTF-8");
87
98
    static iconv_t ic_gbk = iconv_open("GBK", "UTF-8");
93
104
    if (!isCorrectConverted(utf8str, ic_gb, ric_gb)) {
94
105
        ret = 1; // at least it is contains some GBK char
95
106
        if (!isCorrectConverted(utf8str, ic_gbk, ric_gbk))
96
 
            ret = 3; //contains some GB18030-only char
 
107
            ret = 3;  //contains some GB18030-only char
97
108
 
98
109
        #ifdef DEBUG
99
 
            fprintf(stderr, "==> GB category of (%s) is (0x%x)\n ", utf8str, ret);
100
 
            fflush(stderr);
 
110
        fprintf(stderr, "==> GB category of (%s) is (0x%x)\n ", utf8str, ret);
 
111
        fflush(stderr);
101
112
        #endif
102
113
    }
103
114
    return ret;
104
115
}
105
116
#else // !HAVE_ICONV_H
106
 
unsigned getPureGBEncoding(const char* utf8str)
 
117
unsigned
 
118
getPureGBEncoding(const char* utf8str)
107
119
{
108
120
    // FIXME
109
121
    return 0x3;
111
123
#endif // HAVE_ICONV_H
112
124
 
113
125
bool
114
 
parseLine(char* buf, char* word_buf, unsigned& id, std::set<TSyllableInfo>& pyset)
 
126
parseLine(char* buf,
 
127
          char* word_buf,
 
128
          unsigned& id,
 
129
          std::set<TSyllableInfo>& pyset)
115
130
{
116
131
    pyset.clear();
117
132
 
121
136
 
122
137
    char* p = (char*)skipSpace(buf);
123
138
    char* t = (char*)skipNonSpace(p);
124
 
    while(p < t) *word_buf++ = *p++;
 
139
    while (p < t) *word_buf++ = *p++;
125
140
    *word_buf = 0;
126
141
 
127
142
    p = (char*)skipSpace(p);
138
153
        while ((*p >= 'a' && *p <= 'z') || (*p == '\''))
139
154
            ++p;
140
155
        if ((p > s) && ((*p == 0) || (*p == ':'))) {
141
 
            int  cost = 0;
 
156
            int cost = 0;
142
157
            if (*p == ':') {
143
158
                *p++ = 0;
144
 
                cost = atoi(p);
 
159
                cost = -log2(atof(p)/100);
145
160
            }
146
161
            pyset.insert(TSyllableInfo(s, cost));
147
162
        }
152
167
 
153
168
 
154
169
CPinyinTrieMaker::CPinyinTrieMaker()
155
 
    : m_RootNode(), m_StateMap()
156
170
{
157
171
    m_RootNode.m_bExpanded = true;
158
172
}
164
178
        则认为该字段是该词的一个拼音。行长最大4095;
165
179
**********************************************************/
166
180
 
167
 
typedef struct {
168
 
    std::string word_buf;
169
 
    std::string pystr;
170
 
    int         cost;
171
 
    unsigned    gbcategory;
172
 
} TCacheRecord;
173
 
typedef std::vector<TCacheRecord> CWordCache;
174
 
 
175
181
bool
176
182
CPinyinTrieMaker::constructFromLexicon(const char* fileName)
177
183
{
178
 
    CWordCache cached_words;
179
 
 
180
184
    static char buf[4096];
181
185
    static char word_buf[2048];
182
186
 
189
193
    while (fgets(buf, sizeof(buf), fp) != NULL) {
190
194
        if (!parseLine(buf, word_buf, id, pyset)) {
191
195
            if (word_buf[0] != L'<' && word_buf[0] != 0) {
192
 
                if (m_Lexicon.size() < id+1) m_Lexicon.resize(id+1);
 
196
                if (m_Lexicon.size() < id + 1) m_Lexicon.resize(id + 1);
193
197
                m_Lexicon[id] = std::string(word_buf);
194
198
            }
195
199
            continue;
200
204
        std::set<TSyllableInfo>::const_iterator ite = pyset.end();
201
205
        for (; its != ite; ++its) {
202
206
            const char *pystr = its->m_py.c_str();
203
 
            int cost = its->m_cost;
204
 
 
205
 
            if (cost >= 0) {
206
 
                if (m_Lexicon.size() < id+1) m_Lexicon.resize(id+1);
207
 
                m_Lexicon[id] = std::string(word_buf);
208
 
 
209
 
                CPinyinTrieMaker::TWordId wid(id, cost, false, gbcategory);
210
 
                suc = insertFullPinyinPair(pystr, wid) && suc;
211
 
            } else { // cache the rarely seen phonetic
212
 
                TCacheRecord record;
213
 
                record.word_buf   = word_buf;
214
 
                record.pystr      = pystr;
215
 
                record.cost       = cost;
216
 
                record.gbcategory = gbcategory;
217
 
 
218
 
                cached_words.push_back (record);
219
 
            }
 
207
            if (m_Lexicon.size() < id + 1) m_Lexicon.resize(id + 1);
 
208
            m_Lexicon[id] = std::string(word_buf);
 
209
 
 
210
            CPinyinTrieMaker::TWordId wid(id, its->m_cost, false, gbcategory);
 
211
            suc = insertFullPinyinPair(pystr, wid) && suc;
220
212
        }
221
213
    }
222
214
    fclose(fp);
223
215
 
224
 
    // insert the cached words with rarely seen phonetic
225
 
    // FIXME: may use the pinlv information in unicode data later
226
 
    ++id;
227
 
    for (CWordCache::iterator it = cached_words.begin(); it != cached_words.end(); ++it, ++id) {
228
 
        if (m_Lexicon.size() < id+1) m_Lexicon.resize(id+1);
229
 
        m_Lexicon[id] = it->word_buf;
230
 
        int cost = 30 / (-it->cost);
231
 
        CPinyinTrieMaker::TWordId wid(id, cost, true, it->gbcategory);
232
 
        suc = insertFullPinyinPair(it->pystr.c_str(), wid) && suc;
233
 
    }
234
 
 
235
216
    printf("\n    %zd primitive nodes", TNode::m_AllNodes.size());  fflush(stdout);
236
217
 
237
218
    threadNonCompletePinyin();
238
219
    printf("\n    %zd total nodes", TNode::m_AllNodes.size());  fflush(stdout);
239
220
 
240
221
    std::string pyPrefix = "";
241
 
    //print(stderr, &m_RootNode, pyPrefix);
242
222
    printf("\n");  fflush(stdout);
243
223
 
244
224
    return suc;
246
226
 
247
227
CPinyinTrieMaker::CNodeList CPinyinTrieMaker::TNode::m_AllNodes;
248
228
CPinyinTrieMaker::TNode::TNode()
249
 
    : m_bFullSyllableTransfer(false), m_bExpanded(false), m_WordIdSet(),
250
 
      m_Trans(), m_cmbNodes()
 
229
    : m_bExpanded(false), m_bFullSyllableTransfer(false)
251
230
{
252
231
    m_AllNodes.push_back(this);
253
232
}
254
233
 
255
234
bool
256
 
CPinyinTrieMaker::PNodeSet::operator< (const PNodeSet& another) const
 
235
CPinyinTrieMaker::PNodeSet::operator<(const PNodeSet& another) const
257
236
{
258
237
    CNodeSet::const_iterator t1 = m_pns->begin();
259
238
    CNodeSet::const_iterator t2 = m_pns->end();
263
242
        if (*t1 < *a1) return true;
264
243
        if (*t1 > *a1) return false;
265
244
    }
266
 
    return (a1 != a2);
 
245
    return(a1 != a2);
267
246
}
268
247
 
269
248
bool
276
255
    for (; t1 != t2 && a1 != a2; ++t1, ++a1) {
277
256
        if (*t1 != *a1) return false;
278
257
    }
279
 
    return (a1 == a2 && t1 != t2);
 
258
    return(a1 == a2 && t1 != t2);
280
259
}
281
260
 
282
261
static void
283
 
parseFullPinyin (const char *pinyin, std::vector<TSyllable> &ret)
 
262
parseFullPinyin(const char *pinyin, std::vector<TSyllable> &ret)
284
263
{
285
 
    char *buf = strdup (pinyin);
 
264
    char *buf = strdup(pinyin);
286
265
    char *p = buf, *q = buf;
287
266
    ret.clear();
288
267
 
291
270
            *p = '\0';
292
271
            unsigned s = CPinyinData::encodeSyllable(q);
293
272
            if (s)
294
 
                ret.push_back (TSyllable(s));
 
273
                ret.push_back(TSyllable(s));
295
274
            else
296
 
                printf ("\nWarning! unrecognized syllable %s", q);
297
 
            q = p+1;
 
275
                printf("\nWarning! unrecognized syllable %s", q);
 
276
            q = p + 1;
298
277
        }
299
278
        p++;
300
279
    }
301
280
 
302
281
    if (*q) {
303
 
            unsigned s = CPinyinData::encodeSyllable(q);
304
 
            if (s)
305
 
                ret.push_back (TSyllable(s));
306
 
            else
307
 
                printf ("\nWarning! unrecognized syllable %s", q);
 
282
        unsigned s = CPinyinData::encodeSyllable(q);
 
283
        if (s)
 
284
            ret.push_back(TSyllable(s));
 
285
        else
 
286
            printf("\nWarning! unrecognized syllable %s", q);
308
287
    }
309
288
 
310
289
    free(buf);
311
290
}
312
291
 
313
 
void
314
 
CPinyinTrieMaker::print(FILE* fp, TNode* root, std::string& pinyin)
315
 
{
316
 
    if (root && root->m_WordIdSet.size() > 0) {
317
 
        fprintf(fp, "%s", pinyin.c_str());
318
 
        CWordSet::const_iterator itId = root->m_WordIdSet.begin();
319
 
        CWordSet::const_iterator itIdLast = root->m_WordIdSet.end();
320
 
        for (; itId != itIdLast; ++itId) {
321
 
            fprintf(fp, " %s", m_Lexicon[itId->anony.m_id].c_str());
322
 
        }
323
 
        fprintf(fp, "\n");
324
 
    }
325
 
    if (root) {
326
 
        CTrans::const_iterator itTrans = root->m_Trans.begin();
327
 
        CTrans::const_iterator itTransLast = root->m_Trans.end();
328
 
        for (; itTrans != itTransLast; ++itTrans) {
329
 
            const char *str = CPinyinData::decodeSyllable(itTrans->first);
330
 
            pinyin = pinyin + str + '\'';
331
 
            print(fp, itTrans->second, pinyin);
332
 
            pinyin.resize(pinyin.size()-strlen(str)-1);
333
 
        }
334
 
    }
335
 
}
336
 
 
337
292
CPinyinTrieMaker::TNode*
338
293
CPinyinTrieMaker::insertTransfer(TNode* pnode, unsigned s)
339
294
{
354
309
{
355
310
    TNode *pnode = &m_RootNode;
356
311
    std::vector<TSyllable> syllables;
357
 
    parseFullPinyin (pinyin, syllables);
 
312
    parseFullPinyin(pinyin, syllables);
358
313
 
359
314
    if (syllables.empty())
360
315
        return true;
370
325
}
371
326
 
372
327
CPinyinTrieMaker::TNode*
373
 
CPinyinTrieMaker::addCombinedTransfers (TNode *pnode, unsigned s, const CNodeSet& nodes)
 
328
CPinyinTrieMaker::addCombinedTransfers(TNode *pnode,
 
329
                                       unsigned s,
 
330
                                       const CNodeSet& nodes)
374
331
{
375
 
    assert (!nodes.empty());
 
332
    assert(!nodes.empty());
376
333
 
377
334
    TNode *p = NULL;
378
335
    if (nodes.size() == 1) {
384
341
 
385
342
        CNodeSet::const_iterator it = nodes.begin();
386
343
        CNodeSet::const_iterator ite = nodes.end();
387
 
        for (; it != ite; ++it)
388
 
            p->m_WordIdSet.insert ((*it)->m_WordIdSet.begin(), (*it)->m_WordIdSet.end());
 
344
        for (; it != ite; ++it) {
 
345
            CWordSet::const_iterator wit  = (*it)->m_WordIdSet.begin();
 
346
            CWordSet::const_iterator wite = (*it)->m_WordIdSet.end();
 
347
 
 
348
            for (; wit != wite; ++wit) {
 
349
                CWordSet::iterator tmp = p->m_WordIdSet.find (*wit);
 
350
 
 
351
                if (tmp == p->m_WordIdSet.end()) {
 
352
                    p->m_WordIdSet.insert (*wit);
 
353
                } else if (tmp->anony.m_cost > wit->anony.m_cost) {
 
354
                    p->m_WordIdSet.erase (tmp);
 
355
                    p->m_WordIdSet.insert (*wit);
 
356
                }
 
357
            }
 
358
        }
389
359
    }
390
360
 
391
361
    pnode->m_Trans[s] = p;
393
363
}
394
364
 
395
365
void
396
 
CPinyinTrieMaker::combineInitialTrans (TNode *pnode)
 
366
CPinyinTrieMaker::combineInitialTrans(TNode *pnode)
397
367
{
398
368
    std::map<unsigned, CNodeSet> combTrans;
399
369
 
400
370
    CTrans::const_iterator itTrans = pnode->m_Trans.begin();
401
371
    CTrans::const_iterator itTransLast = pnode->m_Trans.end();
402
372
    for (; itTrans != itTransLast; ++itTrans) {
403
 
        TSyllable s = (TSyllable) itTrans->first;
 
373
        TSyllable s = (TSyllable)itTrans->first;
404
374
        if (s.initial) {
405
375
            s.final = s.tone = 0;
406
376
            combTrans[s].insert(itTrans->second);
409
379
 
410
380
    std::map<unsigned, CNodeSet>::const_iterator itCombTrans = combTrans.begin();
411
381
    for (; itCombTrans != combTrans.end(); ++itCombTrans)
412
 
        addCombinedTransfers (pnode, itCombTrans->first, itCombTrans->second);
 
382
        addCombinedTransfers(pnode, itCombTrans->first, itCombTrans->second);
413
383
}
414
384
 
415
385
void
416
 
CPinyinTrieMaker::expandCombinedNode (TNode *pnode)
 
386
CPinyinTrieMaker::expandCombinedNode(TNode *pnode)
417
387
{
418
 
    assert (pnode->m_cmbNodes.size() >= 1);
 
388
    assert(pnode->m_cmbNodes.size() >= 1);
419
389
 
420
390
    std::map<unsigned, CNodeSet> combTrans;
421
391
    CNodeSet::const_iterator itNode = pnode->m_cmbNodes.begin();
428
398
    }
429
399
 
430
400
    std::map<unsigned, CNodeSet>::const_iterator itCombTrans = combTrans.begin();
431
 
    for (; itCombTrans != combTrans.end(); ++itCombTrans)  {
 
401
    for (; itCombTrans != combTrans.end(); ++itCombTrans) {
432
402
        TNode* p = NULL;
433
403
        unsigned s = itCombTrans->first;
434
404
        CNodeSet nodes = itCombTrans->second;
437
407
        if (itStateMap != m_StateMap.end())
438
408
            p = itStateMap->second;
439
409
        else
440
 
            p = addCombinedTransfers (pnode, s, nodes);
 
410
            p = addCombinedTransfers(pnode, s, nodes);
441
411
 
442
412
        pnode->m_Trans[s] = p;
443
413
    }
452
422
    for (; itNode != TNode::m_AllNodes.end(); ++itNode) {
453
423
        TNode* pnode = *itNode;
454
424
        if (pnode->m_bExpanded)
455
 
            combineInitialTrans (pnode);
 
425
            combineInitialTrans(pnode);
456
426
        else
457
 
            expandCombinedNode (pnode);
 
427
            expandCombinedNode(pnode);
458
428
    }
459
429
    return true;
460
430
}
498
468
    for (; itWordStr != itWordStrLast; ++itWordStr) {
499
469
        MBSTOWCS(wbuf, itWordStr->c_str(), 1024);
500
470
        int sz = WCSLEN(wbuf);
501
 
        offset += (sz+1)*sizeof(TWCHAR);
 
471
        offset += (sz + 1) * sizeof(TWCHAR);
502
472
    }
503
473
 
504
474
    Writer f(fp, revert_endian);
505
 
    
 
475
 
506
476
    suc = f.write(nWord);
507
477
    suc = f.write(nNode);
508
478
    suc = f.write(lexiconOffset);
509
479
 
510
480
    itNode = TNode::m_AllNodes.begin();
511
481
    itNodeLast = TNode::m_AllNodes.end();
512
 
    
 
482
 
513
483
    for (; itNode != itNodeLast && suc; ++itNode) {
514
484
        CPinyinTrie::TNode outNode;
515
485
        TNode *pnode = *itNode;
521
491
 
522
492
        CWordSet::const_iterator itId = pnode->m_WordIdSet.begin();
523
493
        CWordSet::const_iterator itIdLast = pnode->m_WordIdSet.end();
524
 
        for (; itId != itIdLast && outNode.m_csLevel<3; ++itId) {
 
494
        for (; itId != itIdLast && outNode.m_csLevel < 3; ++itId) {
525
495
            if (outNode.m_csLevel < itId->anony.m_csLevel)
526
496
                outNode.m_csLevel = itId->anony.m_csLevel;
527
497
        }
542
512
        itId = pnode->m_WordIdSet.begin();
543
513
        itIdLast = pnode->m_WordIdSet.end();
544
514
        for (; itId != itIdLast; ++itId)
545
 
            vec.push_back(TWordInfo(*itId, psrt->getCost(*itId), psrt->isSeen(*itId)));
 
515
            vec.push_back(TWordInfo(*itId, psrt->getCost(*itId) + itId->anony.m_cost,
 
516
                                    psrt->isSeen(*itId)));
546
517
        std::make_heap(vec.begin(), vec.end());
547
518
        std::sort_heap(vec.begin(), vec.end());
548
519
 
551
522
        for (; itv != itve && suc; ++itv) {
552
523
            CPinyinTrie::TWordIdInfo wi;
553
524
            wi.m_id = itv->m_id.anony.m_id;
554
 
            assert (wi.m_id < nWord);
 
525
            assert(wi.m_id < nWord);
555
526
            wi.m_csLevel = itv->m_id.anony.m_csLevel;
556
 
            wi.m_bSeen = ((itv->m_bSeen)?(1):(0));
 
527
            wi.m_bSeen = ((itv->m_bSeen) ? (1) : (0));
557
528
            wi.m_cost = itv->m_id.anony.m_cost;
558
529
            suc = f.write(wi);
559
530
        }
564
535
    for (; itWordStr != itWordStrLast && suc; ++itWordStr) {
565
536
        MBSTOWCS(wbuf, itWordStr->c_str(), 1024);
566
537
        int sz = WCSLEN(wbuf);
567
 
        suc = f.write(wbuf, (sz+1));
 
538
        suc = f.write(wbuf, (sz + 1));
568
539
    }
569
540
    return suc;
570
541
}