~ubuntu-branches/ubuntu/raring/sunpinyin/raring

« back to all changes in this revision

Viewing changes to src/pinyin/pinyin_seg.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:
1
1
/*
2
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 
 * 
 
3
 *
4
4
 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
5
 
 * 
 
5
 *
6
6
 * The contents of this file are subject to the terms of either the GNU Lesser
7
7
 * General Public License Version 2.1 only ("LGPL") or the Common Development and
8
8
 * Distribution License ("CDDL")(collectively, the "License"). You may not use this
9
9
 * file except in compliance with the License. You can obtain a copy of the CDDL at
10
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 
 
11
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
12
12
 * specific language governing permissions and limitations under the License. When
13
13
 * distributing the software, include this License Header Notice in each file and
14
14
 * include the full text of the License in the License file as well as the
15
15
 * following notice:
16
 
 * 
 
16
 *
17
17
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
18
18
 * (CDDL)
19
19
 * For Covered Software in this distribution, this License shall be governed by the
21
21
 * Any litigation relating to this License shall be subject to the jurisdiction of
22
22
 * the Federal Courts of the Northern District of California and the state courts
23
23
 * of the State of California, with venue lying in Santa Clara County, California.
24
 
 * 
 
24
 *
25
25
 * Contributor(s):
26
 
 * 
 
26
 *
27
27
 * If you wish your version of this file to be governed by only the CDDL or only
28
28
 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
29
29
 * include this software in this distribution under the [CDDL or LGPL Version 2.1]
32
32
 * Version 2.1, or to extend the choice of license to its licensees as provided
33
33
 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
34
34
 * Version 2 license, then the option applies only if the new code is made subject
35
 
 * to such option by the copyright holder. 
 
35
 * to such option by the copyright holder.
36
36
 */
37
37
 
38
38
#include <cassert>
41
41
#include "pinyin_seg.h"
42
42
#include "quanpin_trie.h"
43
43
 
44
 
const char * CGetCorrectionPairOp::operator () (std::string& pystr, unsigned& matched_len)
 
44
const char *
 
45
CGetCorrectionPairOp::operator ()(std::string& pystr, unsigned& matched_len)
45
46
{
46
 
    CCorrectionPairVec::iterator it  = m_correctionPairs.begin ();
47
 
    CCorrectionPairVec::iterator ite = m_correctionPairs.end ();
 
47
    CCorrectionPairVec::iterator it = m_correctionPairs.begin();
 
48
    CCorrectionPairVec::iterator ite = m_correctionPairs.end();
48
49
 
49
50
    for (; it != ite; ++it) {
50
51
        std::string& k = it->first;
51
52
        std::string& v = it->second;
52
 
        unsigned l = k.size ();
 
53
        unsigned l = k.size();
53
54
 
54
 
        if (pystr.size() >= l && !pystr.compare (pystr.size()-l, l, k)) {
 
55
        if (pystr.size() >= l && !pystr.compare(pystr.size() - l, l, k)) {
55
56
            matched_len = l;
56
57
            return v.c_str();
57
58
        }
60
61
    return NULL;
61
62
}
62
63
 
63
 
void CGetFuzzySegmentsOp::_initMaps ()
 
64
void
 
65
CGetFuzzySegmentsOp::_initMaps()
64
66
{
65
67
    unsigned num_of_fuzzy_finals;
66
 
    const unsigned * fuzzy_final_map = CPinyinData::getInnerFuzzyFinalMap (num_of_fuzzy_finals);
67
 
    
68
 
    for (int i = 0; i < num_of_fuzzy_finals; ++i)
69
 
    {
70
 
        unsigned  f = *(fuzzy_final_map++);
 
68
    const unsigned * fuzzy_final_map = CPinyinData::getInnerFuzzyFinalMap(
 
69
        num_of_fuzzy_finals);
 
70
 
 
71
    for (size_t i = 0; i < num_of_fuzzy_finals; ++i) {
 
72
        unsigned f = *(fuzzy_final_map++);
71
73
        unsigned _f = *(fuzzy_final_map++);
72
 
        unsigned  l = *(fuzzy_final_map++);
73
 
    
74
 
        m_fuzzyFinalMap.insert (std::make_pair(f, std::make_pair(_f, l)));
 
74
        unsigned l = *(fuzzy_final_map++);
 
75
 
 
76
        m_fuzzyFinalMap.insert(std::make_pair(f, std::make_pair(_f, l)));
75
77
    }
76
78
 
77
79
    const unsigned *fuzzy_pre_syls, *fuzzy_pro_syls;
78
 
    CPinyinData::getFuzzyPreProSyllables (&fuzzy_pre_syls, &fuzzy_pro_syls);
 
80
    CPinyinData::getFuzzyPreProSyllables(&fuzzy_pre_syls, &fuzzy_pro_syls);
79
81
 
80
82
    while (*fuzzy_pre_syls) {
81
 
        unsigned  s = *(fuzzy_pre_syls++);
82
 
        char      c = *(fuzzy_pre_syls++);
 
83
        unsigned s = *(fuzzy_pre_syls++);
 
84
        char c = *(fuzzy_pre_syls++);
83
85
        unsigned _s = *(fuzzy_pre_syls++);
84
 
        m_fuzzyPreMap.insert (std::make_pair(s, std::make_pair(c, _s)));
 
86
        m_fuzzyPreMap.insert(std::make_pair(s, std::make_pair(c, _s)));
85
87
    }
86
88
 
87
89
    while (*fuzzy_pro_syls) {
88
 
        unsigned  s = *(fuzzy_pro_syls++);
89
 
        char      c = *(fuzzy_pro_syls++);
 
90
        unsigned s = *(fuzzy_pro_syls++);
 
91
        char c = *(fuzzy_pro_syls++);
90
92
        unsigned _s = *(fuzzy_pro_syls++);
91
 
        m_fuzzyProMap.insert (std::make_pair(s, std::make_pair(c, _s)));
 
93
        m_fuzzyProMap.insert(std::make_pair(s, std::make_pair(c, _s)));
92
94
    }
93
95
}
94
96
 
95
 
unsigned CGetFuzzySegmentsOp::_invalidateSegments (IPySegmentor::TSegmentVec& fuzzy_segs, IPySegmentor::TSegment& seg)
 
97
unsigned
 
98
CGetFuzzySegmentsOp::_invalidateSegments(IPySegmentor::TSegmentVec& fuzzy_segs,
 
99
                                         IPySegmentor::TSegment& seg)
96
100
{
97
101
    unsigned invalidatedFrom = UINT_MAX;
98
102
 
99
 
    IPySegmentor::TSegmentVec::reverse_iterator it  = fuzzy_segs.rbegin();
 
103
    IPySegmentor::TSegmentVec::reverse_iterator it = fuzzy_segs.rbegin();
100
104
    IPySegmentor::TSegmentVec::reverse_iterator ite = fuzzy_segs.rend();
101
105
 
102
 
    for (; it != ite; it+=2)
103
 
    {
104
 
        IPySegmentor::TSegment& seg1 = *(it+1);
 
106
    for (; it != ite; it += 2) {
 
107
        IPySegmentor::TSegment& seg1 = *(it + 1);
105
108
        IPySegmentor::TSegment& seg2 = *it;
106
109
 
107
 
        unsigned r = seg2.m_start+seg2.m_len;
 
110
        unsigned r = seg2.m_start + seg2.m_len;
108
111
        if (r <= seg.m_start)
109
112
            break;
110
113
 
111
114
        invalidatedFrom = seg1.m_start;
112
115
    }
113
116
 
114
 
    fuzzy_segs.erase (it.base(), fuzzy_segs.end());
 
117
    fuzzy_segs.erase(it.base(), fuzzy_segs.end());
115
118
 
116
119
    return invalidatedFrom;
117
120
}
118
121
 
119
 
unsigned CGetFuzzySegmentsOp::operator () (IPySegmentor::TSegmentVec& segs, IPySegmentor::TSegmentVec& fuzzy_segs, wstring& input)
 
122
unsigned
 
123
CGetFuzzySegmentsOp::operator ()(IPySegmentor::TSegmentVec& segs,
 
124
                                 IPySegmentor::TSegmentVec& fuzzy_segs,
 
125
                                 wstring& input)
120
126
{
121
127
    IPySegmentor::TSegment&  seg = segs.back();
122
 
    unsigned invalidatedFrom = _invalidateSegments (fuzzy_segs, seg);
 
128
    unsigned invalidatedFrom = _invalidateSegments(fuzzy_segs, seg);
123
129
 
124
130
    unsigned updatedFrom = UINT_MAX;
125
 
    TSyllable syl = (TSyllable) seg.m_syllables[0];
126
 
 
127
 
    if (m_bInnerFuzzyEnabled)
128
 
    { // xian -> xian, xi'an
129
 
        CInnerFuzzyFinalMap::iterator it = m_fuzzyFinalMap.find (syl.final);
130
 
 
131
 
        if (it != m_fuzzyFinalMap.end())
132
 
        {
133
 
            unsigned    an_syl = it->second.first;
134
 
            unsigned    an_len = it->second.second;
135
 
 
136
 
            unsigned    xi_len = seg.m_len - an_len;
137
 
            wstring     wstr   = input.substr (seg.m_start, xi_len);
 
131
    TSyllable syl = (TSyllable)seg.m_syllables[0];
 
132
 
 
133
    if (m_bInnerFuzzyEnabled) { // xian -> xian, xi'an
 
134
        CInnerFuzzyFinalMap::iterator it = m_fuzzyFinalMap.find(syl.final);
 
135
 
 
136
        if (it != m_fuzzyFinalMap.end()) {
 
137
            unsigned an_syl = it->second.first;
 
138
            unsigned an_len = it->second.second;
 
139
 
 
140
            unsigned xi_len = seg.m_len - an_len;
 
141
            wstring wstr = input.substr(seg.m_start, xi_len);
138
142
 
139
143
#ifndef _RW_STD_STL
140
 
            std::string xi_str (wstr.begin(), wstr.end());
 
144
            std::string xi_str(wstr.begin(), wstr.end());
141
145
#else
142
146
            std::string xi_str;
143
147
            for (wstring::iterator it = wstr.begin(); it != wstr.end(); ++it)
144
 
                xi_str.push_back (*it);
 
148
                xi_str.push_back(*it);
145
149
#endif
146
150
 
147
 
            unsigned    xi_syl = CPinyinData::encodeSyllable (xi_str.c_str());
 
151
            unsigned xi_syl = CPinyinData::encodeSyllable(xi_str.c_str());
148
152
 
149
153
            if (0 == xi_syl)
150
154
                goto RETURN;
151
 
            
 
155
 
152
156
            IPySegmentor::TSegment xi = segs.back();
153
157
            xi.m_len = xi_len;
154
158
            xi.m_syllables[0] = xi_syl;
155
159
 
156
160
            IPySegmentor::TSegment an = segs.back();
157
 
            an.m_len    = an_len;
 
161
            an.m_len = an_len;
158
162
            an.m_start += xi_len;
159
163
            an.m_syllables[0] = an_syl;
160
164
            an.m_inner_fuzzy = true;
161
165
 
162
 
            fuzzy_segs.push_back (xi);
163
 
            fuzzy_segs.push_back (an);
 
166
            fuzzy_segs.push_back(xi);
 
167
            fuzzy_segs.push_back(an);
164
168
 
165
169
            updatedFrom = xi.m_start;
166
170
            goto RETURN;
170
174
    if (segs.size() >= 2) { // fangan -> fang'an, fan'gan
171
175
        IPySegmentor::TSegment& pre_seg = *(segs.end() - 2);
172
176
 
173
 
        CFuzzySyllableMap::iterator pre_it = m_fuzzyPreMap.find (pre_seg.m_syllables[0]);
174
 
        CFuzzySyllableMap::iterator     it = m_fuzzyProMap.find (syl);
 
177
        CFuzzySyllableMap::iterator pre_it = m_fuzzyPreMap.find(
 
178
            pre_seg.m_syllables[0]);
 
179
        CFuzzySyllableMap::iterator it = m_fuzzyProMap.find(syl);
175
180
 
176
181
        if (pre_it != m_fuzzyPreMap.end() && it != m_fuzzyProMap.end() &&
177
 
            pre_it->second.first == it->second.first)
178
 
        {
179
 
            IPySegmentor::TSegment fang = segs[segs.size()-2];
180
 
            fang.m_len ++;
 
182
            pre_it->second.first == it->second.first) {
 
183
            IPySegmentor::TSegment fang = segs[segs.size() - 2];
 
184
            fang.m_len++;
181
185
            fang.m_syllables[0] = pre_it->second.second;
182
186
 
183
187
            IPySegmentor::TSegment an = segs.back();
184
 
            an.m_start ++;
185
 
            an.m_len --;
 
188
            an.m_start++;
 
189
            an.m_len--;
186
190
            an.m_syllables[0] = it->second.second;
187
191
 
188
 
            fuzzy_segs.push_back (fang);
189
 
            fuzzy_segs.push_back (an);
 
192
            fuzzy_segs.push_back(fang);
 
193
            fuzzy_segs.push_back(an);
190
194
 
191
195
            updatedFrom = fang.m_start;
192
196
            goto RETURN;
195
199
 
196
200
RETURN:;
197
201
 
198
 
    return std::min (updatedFrom, invalidatedFrom);
 
202
    return std::min(updatedFrom, invalidatedFrom);
199
203
}
200
204
 
201
205
 
202
 
CQuanpinSegmentor::CQuanpinSegmentor () 
203
 
    : m_updatedFrom(0),
204
 
      m_pGetFuzzySyllablesOp(NULL),
 
206
CQuanpinSegmentor::CQuanpinSegmentor ()
 
207
    : m_pGetFuzzySyllablesOp(NULL),
205
208
      m_pGetCorrectionPairOp(NULL),
206
209
      m_pGetFuzzySegmentsOp(NULL),
207
 
      m_pytrie(base, check, value, sizeof(base)/sizeof(*base))
 
210
      m_pytrie(base, check, value, sizeof(base) / sizeof(*base)),
 
211
      m_updatedFrom(0)
208
212
{
209
 
    m_segs.reserve (32);
 
213
    m_segs.reserve(32);
210
214
}
211
215
 
212
 
bool CQuanpinSegmentor::load(const char * pyTrieFileName)
 
216
bool
 
217
CQuanpinSegmentor::load(const char * pyTrieFileName)
213
218
{
214
 
    return m_pytrie.load (pyTrieFileName);
 
219
    return m_pytrie.load(pyTrieFileName);
215
220
}
216
221
 
217
222
#ifdef DEBUG
218
 
void print_pystr(const std::string pystr)
 
223
void
 
224
print_pystr(const std::string pystr)
219
225
{
220
 
    for (const char* c = pystr.c_str(); c != pystr.c_str() + pystr.length(); ++c)
221
 
    {
 
226
    for (const char* c = pystr.c_str();
 
227
         c != pystr.c_str() + pystr.length();
 
228
         ++c) {
222
229
        printf("%c", *c & 0x7f);
223
230
    }
224
231
    printf("<\n");
225
232
}
226
233
#endif
227
234
 
228
 
unsigned CQuanpinSegmentor::push (unsigned ch)
 
235
unsigned
 
236
CQuanpinSegmentor::push(unsigned ch)
229
237
{
230
 
    m_inputBuf.push_back (ch);
 
238
    m_inputBuf.push_back(ch);
231
239
 
232
240
    if (m_pGetCorrectionPairOp && m_pGetCorrectionPairOp->isEnabled()) {
233
 
        m_pystr.push_back (ch);
 
241
        m_pystr.push_back(ch);
234
242
        unsigned l = 0;
235
 
        const char * v = (*m_pGetCorrectionPairOp) (m_pystr, l);
 
243
        const char * v = (*m_pGetCorrectionPairOp)(m_pystr, l);
236
244
 
237
245
        if (v) {
238
246
            unsigned orig_size = m_segs.size();
239
 
            _clear (m_pystr.size() - l);
240
 
            m_updatedFrom = _updateWith (v);
241
 
            
242
 
            if (m_segs.size () >= orig_size) {
 
247
            _clear(m_pystr.size() - l);
 
248
            m_updatedFrom = _updateWith(v);
 
249
 
 
250
            if (m_segs.size() >= orig_size) {
243
251
                // does not get better segmentation, revert to original
244
 
                _clear (m_pystr.size() - strlen(v));
 
252
                _clear(m_pystr.size() - strlen(v));
245
253
                std::string new_pystr;
246
 
                std::copy(m_inputBuf.end() - l, m_inputBuf.end(), back_inserter(new_pystr));
247
 
                m_updatedFrom = _updateWith (new_pystr);
 
254
                std::copy(m_inputBuf.end() - l, m_inputBuf.end(),
 
255
                          back_inserter(new_pystr));
 
256
                m_updatedFrom = _updateWith(new_pystr);
248
257
            } else {
249
258
                if (l != strlen(v)) {
250
259
                    // e.g. uen -> un
251
260
                    m_segs.back().m_len += l - strlen(v);
252
261
                    m_pystr.resize(m_inputBuf.length());
253
262
                }
254
 
                std::copy(m_inputBuf.end() - l, m_inputBuf.end(), m_pystr.end() - l);
 
263
                std::copy(m_inputBuf.end() - l, m_inputBuf.end(),
 
264
                          m_pystr.end() - l);
255
265
            }
256
266
            return m_updatedFrom;
257
267
        }
258
268
 
259
 
        m_pystr.resize (m_pystr.size() - 1);
 
269
        m_pystr.resize(m_pystr.size() - 1);
260
270
    }
261
271
 
262
 
    return m_updatedFrom = _push (ch);
 
272
    return m_updatedFrom = _push(ch);
263
273
}
264
274
 
265
 
unsigned CQuanpinSegmentor::pop ()
 
275
unsigned
 
276
CQuanpinSegmentor::pop()
266
277
{
267
278
    if (m_pystr.empty())
268
279
        return m_updatedFrom = 0;
269
280
 
270
 
    unsigned size = m_inputBuf.size ();
271
 
    m_inputBuf.resize (size - 1);
272
 
    m_pystr.resize (size - 1);
 
281
    unsigned size = m_inputBuf.size();
 
282
    m_inputBuf.resize(size - 1);
 
283
    m_pystr.resize(size - 1);
273
284
 
274
285
    unsigned l = m_segs.back().m_len;
275
 
    m_segs.pop_back ();
 
286
    m_segs.pop_back();
276
287
 
277
 
    if (l == 1) 
 
288
    if (l == 1)
278
289
        return m_updatedFrom = size - 1;
279
290
 
280
 
    std::string new_pystr = m_pystr.substr (size-l);
281
 
    m_pystr.resize (size-l);
 
291
    std::string new_pystr = m_pystr.substr(size - l);
 
292
    m_pystr.resize(size - l);
282
293
 
283
294
    m_updatedFrom = _updateWith(new_pystr);
284
295
 
285
296
    return m_updatedFrom;
286
297
}
287
298
 
288
 
unsigned CQuanpinSegmentor::insertAt (unsigned idx, unsigned ch)
 
299
unsigned
 
300
CQuanpinSegmentor::insertAt(unsigned idx, unsigned ch)
289
301
{
290
302
    unsigned i, j;
291
 
    _locateSegment (idx, i, j);
292
 
 
293
 
    m_inputBuf.insert (idx, 1, ch);
294
 
    m_pystr.insert (idx, 1, ch);
295
 
 
296
 
    std::string new_pystr = m_pystr.substr (i);
297
 
    m_pystr.resize (i);
298
 
    m_segs.erase (m_segs.begin()+j, m_segs.end());
299
 
 
300
 
    m_updatedFrom = _updateWith (new_pystr);
 
303
    _locateSegment(idx, i, j);
 
304
 
 
305
    m_inputBuf.insert(idx, 1, ch);
 
306
    m_pystr.insert(idx, 1, ch);
 
307
 
 
308
    std::string new_pystr = m_pystr.substr(i);
 
309
    m_pystr.resize(i);
 
310
    m_segs.erase(m_segs.begin() + j, m_segs.end());
 
311
 
 
312
    m_updatedFrom = _updateWith(new_pystr);
301
313
 
302
314
    return m_updatedFrom;
303
315
}
304
316
 
305
 
unsigned CQuanpinSegmentor::deleteAt (unsigned idx, bool backward)
 
317
unsigned
 
318
CQuanpinSegmentor::deleteAt(unsigned idx, bool backward)
306
319
{
307
320
    unsigned i, j;
308
321
    if (!backward) idx += 1;
309
 
    _locateSegment (idx, i, j);
310
 
 
311
 
    m_inputBuf.erase (idx, 1);
312
 
    m_pystr.erase (idx, 1);
313
 
 
314
 
    std::string new_pystr = m_pystr.substr (i);
315
 
    m_pystr.resize (i);
316
 
    m_segs.erase (m_segs.begin()+j, m_segs.end());
317
 
 
318
 
    m_updatedFrom = _updateWith (new_pystr);
 
322
    _locateSegment(idx, i, j);
 
323
 
 
324
    m_inputBuf.erase(idx, 1);
 
325
    m_pystr.erase(idx, 1);
 
326
 
 
327
    std::string new_pystr = m_pystr.substr(i);
 
328
    m_pystr.resize(i);
 
329
    m_segs.erase(m_segs.begin() + j, m_segs.end());
 
330
 
 
331
    m_updatedFrom = _updateWith(new_pystr);
319
332
 
320
333
    return m_updatedFrom;
321
334
}
322
335
 
323
 
unsigned CQuanpinSegmentor::clear (unsigned from)
 
336
unsigned
 
337
CQuanpinSegmentor::clear(unsigned from)
324
338
{
325
 
    m_inputBuf.resize (from);
326
 
    return _clear (from);
 
339
    m_inputBuf.resize(from);
 
340
    return _clear(from);
327
341
}
328
342
 
329
 
unsigned CQuanpinSegmentor::_clear (unsigned from)
 
343
unsigned
 
344
CQuanpinSegmentor::_clear(unsigned from)
330
345
{
331
346
    unsigned i, j;
332
 
    _locateSegment (from, i, j);
333
 
 
334
 
 
335
 
    std::string new_pystr = m_pystr.substr (i, from-i);
336
 
    m_pystr.resize (i);
337
 
    m_segs.erase (m_segs.begin()+j, m_segs.end());
338
 
 
339
 
    m_updatedFrom = _updateWith (new_pystr, from);
 
347
    _locateSegment(from, i, j);
 
348
 
 
349
 
 
350
    std::string new_pystr = m_pystr.substr(i, from - i);
 
351
    m_pystr.resize(i);
 
352
    m_segs.erase(m_segs.begin() + j, m_segs.end());
 
353
 
 
354
    m_updatedFrom = _updateWith(new_pystr, from);
340
355
 
341
356
    return m_updatedFrom;
342
357
}
343
358
 
344
 
void CQuanpinSegmentor::_locateSegment (unsigned idx, unsigned &strIdx, unsigned &segIdx)
 
359
void
 
360
CQuanpinSegmentor::_locateSegment(unsigned idx,
 
361
                                  unsigned &strIdx,
 
362
                                  unsigned &segIdx)
345
363
{
346
364
    strIdx = segIdx = 0;
347
365
 
348
 
    TSegmentVec::iterator it  = m_segs.begin();
 
366
    TSegmentVec::iterator it = m_segs.begin();
349
367
    TSegmentVec::iterator ite = m_segs.end();
350
368
 
351
369
    for (; it != ite; ++it) {
352
370
        if (strIdx + (*it).m_len > idx)
353
 
           break; 
 
371
            break;
354
372
 
355
373
        strIdx += (*it).m_len;
356
374
        segIdx += 1;
357
375
    }
358
376
}
359
377
 
360
 
unsigned CQuanpinSegmentor::_push (unsigned ch)
 
378
unsigned
 
379
CQuanpinSegmentor::_push(unsigned ch)
361
380
{
362
381
    unsigned l, ret;
363
 
    m_pystr.push_back (ch);
364
 
    int v = m_pytrie.match_longest (m_pystr.rbegin(), m_pystr.rend(), l);
 
382
    m_pystr.push_back(ch);
 
383
    int v = m_pytrie.match_longest(m_pystr.rbegin(), m_pystr.rend(), l);
365
384
 
366
385
    if (l == 0) { // not a valid syllable character, e.g., \', i, u, or A-Z
367
386
        IPySegmentor::ESegmentType seg_type;
368
387
        if (ch == '\'' && m_inputBuf.size() > 1)
369
388
            seg_type = IPySegmentor::SYLLABLE_SEP;
370
 
        else if (islower (ch))
 
389
        else if (islower(ch))
371
390
            seg_type = IPySegmentor::INVALID;
372
391
        else
373
392
            seg_type = IPySegmentor::STRING;
374
393
 
375
 
        ret = m_pystr.size () - 1;
376
 
        m_segs.push_back (TSegment (ch, ret, 1, seg_type));
377
 
    }
378
 
 
379
 
    else if (l == 1) { // possible a new segment
380
 
        int last_idx = m_pystr.size () - 2;
381
 
        if ( last_idx >= 0 && (m_pystr[last_idx] & 0x80)) {
 
394
        ret = m_pystr.size() - 1;
 
395
        m_segs.push_back(TSegment(ch, ret, 1, seg_type));
 
396
    } else if (l == 1) { // possible a new segment
 
397
        int last_idx = m_pystr.size() - 2;
 
398
        if (last_idx >= 0 && (m_pystr[last_idx] & 0x80)) {
382
399
            // check if the last syllable character's highest bitmask is set
383
400
            // e.g., feN, so [feN] + g -> [feng]
384
401
            m_pystr[last_idx] &= 0x7f;
385
402
            unsigned l;
386
 
            int v = m_pytrie.match_longest (m_pystr.rbegin(), m_pystr.rend(), l);
 
403
            int v = m_pytrie.match_longest(m_pystr.rbegin(), m_pystr.rend(), l);
387
404
 
388
405
            TSegment &last_seg = m_segs.back();
389
 
            if (l == last_seg.m_len + 1) {
 
406
            if (l == (unsigned) last_seg.m_len + 1) {
390
407
                last_seg.m_len += 1;
391
408
                last_seg.m_syllables[0] = v;
392
409
                ret = m_pystr.size() - l;
398
415
        }
399
416
 
400
417
        // push the new 1-length segment
401
 
        ret = m_pystr.size () - 1;
402
 
        m_segs.push_back (TSegment (v, ret, 1));
403
 
    }
404
 
 
405
 
    else if (l == m_segs.back().m_len + 1) { // current segment is extensible, e.g., [xia] + n -> [xian]
406
 
        TSegment &last_seg = m_segs.back ();
 
418
        ret = m_pystr.size() - 1;
 
419
        m_segs.push_back(TSegment(v, ret, 1));
 
420
    } else if (l == (unsigned) m_segs.back().m_len + 1) {
 
421
        // current segment is extensible, e.g., [xia] + n -> [xian]
 
422
        TSegment &last_seg = m_segs.back();
407
423
        last_seg.m_len += 1;
408
424
        last_seg.m_syllables[0] = v;
409
425
        ret = m_pystr.size() - l;
410
 
    }
411
 
 
412
 
    else { // other cases
413
 
        TSegment &last_seg = m_segs.back ();
 
426
    } else {  // other cases
 
427
        TSegment &last_seg = m_segs.back();
414
428
        int i = 0, isum = last_seg.m_len + 1, lsum = l;
415
 
        TSegmentVec new_segs(1, TSegment(v, m_pystr.size()-l, l));
 
429
        TSegmentVec new_segs(1, TSegment(v, m_pystr.size() - l, l));
416
430
 
417
 
        // e.g., [zh] [o] [n] + g -> [zhonG], 
 
431
        // e.g., [zh] [o] [n] + g -> [zhonG],
418
432
        if (isum < lsum) {
419
 
            unsigned end_idx = m_pystr.size () - 1;
 
433
            unsigned end_idx = m_pystr.size() - 1;
420
434
            m_pystr[end_idx] |= 0x80;
421
435
        }
422
436
 
423
437
        while (isum != lsum) {
424
438
            if (lsum < isum) { // e.g., [die] + r -> [di] [er]
425
 
                v = m_pytrie.match_longest (m_pystr.rbegin()+lsum, m_pystr.rend(), l);
426
 
                TSegment &last_seg = new_segs.back ();
427
 
                new_segs.push_back (TSegment(v, last_seg.m_start-l, l));
428
 
                _addFuzzySyllables (new_segs.back ());
 
439
                v = m_pytrie.match_longest(
 
440
                    m_pystr.rbegin() + lsum, m_pystr.rend(), l);
 
441
                TSegment &last_seg = new_segs.back();
 
442
                new_segs.push_back(TSegment(v, last_seg.m_start - l, l));
 
443
                _addFuzzySyllables(new_segs.back());
429
444
                lsum += l;
430
445
            } else {
431
446
                i += 1;
433
448
            }
434
449
        }
435
450
 
436
 
        m_segs.erase (m_segs.end()-(i+1), m_segs.end());
437
 
        std::copy (new_segs.rbegin(), new_segs.rend(), back_inserter (m_segs));
438
 
        ret = m_pystr.size()-lsum;
 
451
        m_segs.erase(m_segs.end() - (i + 1), m_segs.end());
 
452
        std::copy(new_segs.rbegin(), new_segs.rend(), back_inserter(m_segs));
 
453
        ret = m_pystr.size() - lsum;
439
454
    }
440
455
 
441
456
RETURN:;
442
457
 
443
458
    if (m_pGetFuzzySegmentsOp && m_pGetFuzzySegmentsOp->isEnabled())
444
 
        ret = std::min (ret, (*m_pGetFuzzySegmentsOp) (m_segs, m_fuzzy_segs, m_inputBuf));
 
459
        ret =
 
460
            std::min(ret,
 
461
                     (*m_pGetFuzzySegmentsOp)(m_segs, m_fuzzy_segs, m_inputBuf));
445
462
 
446
463
    if (m_pGetFuzzySyllablesOp && m_pGetFuzzySyllablesOp->isEnabled()) {
447
 
 
448
464
        if (m_segs.back().m_type == SYLLABLE)
449
 
            _addFuzzySyllables (m_segs.back ());
 
465
            _addFuzzySyllables(m_segs.back());
450
466
 
451
467
        if (m_fuzzy_segs.size()) {
452
 
            _addFuzzySyllables (*(m_fuzzy_segs.end()-1));
453
 
            _addFuzzySyllables (*(m_fuzzy_segs.end()-2));
 
468
            _addFuzzySyllables(*(m_fuzzy_segs.end() - 1));
 
469
            _addFuzzySyllables(*(m_fuzzy_segs.end() - 2));
454
470
        }
455
 
 
456
471
    }
457
472
 
458
473
    return ret;
459
474
}
460
475
 
461
 
void CQuanpinSegmentor::_addFuzzySyllables (TSegment& seg)
 
476
void
 
477
CQuanpinSegmentor::_addFuzzySyllables(TSegment& seg)
462
478
{
463
 
    assert (seg.m_type == SYLLABLE);
 
479
    assert(seg.m_type == SYLLABLE);
464
480
 
465
481
    seg.m_fuzzy_syllables.clear();
466
482
 
467
 
    CSyllables fuzzy_set = (*m_pGetFuzzySyllablesOp) (seg.m_syllables.front());
468
 
    CSyllables::const_iterator it  = fuzzy_set.begin ();
469
 
    CSyllables::const_iterator ite = fuzzy_set.end ();
470
 
    
 
483
    CSyllables fuzzy_set = (*m_pGetFuzzySyllablesOp)(seg.m_syllables.front());
 
484
    CSyllables::const_iterator it = fuzzy_set.begin();
 
485
    CSyllables::const_iterator ite = fuzzy_set.end();
 
486
 
471
487
    for (; it != ite; ++it)
472
 
        seg.m_fuzzy_syllables.push_back (*it);
 
488
        seg.m_fuzzy_syllables.push_back(*it);
473
489
}
474
490
 
475
 
unsigned CQuanpinSegmentor::_updateWith (const std::string& new_pystr, unsigned from)
 
491
unsigned
 
492
CQuanpinSegmentor::_updateWith(const std::string& new_pystr, unsigned from)
476
493
{
477
494
    unsigned minUpdatedFrom = from;
478
495
    std::string::const_iterator it = new_pystr.begin();
479
496
    for (; it != new_pystr.end(); ++it) {
480
497
        unsigned updatedFrom = _push(*it & 0x7f);
481
 
        
 
498
 
482
499
        if (updatedFrom < minUpdatedFrom) minUpdatedFrom = updatedFrom;
483
500
    }
484
501
    return minUpdatedFrom;