react-native-jieba 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Jieba.podspec +30 -0
- package/LICENSE +20 -0
- package/README.md +103 -0
- package/android/CMakeLists.txt +29 -0
- package/android/build.gradle +60 -0
- package/android/generated/java/com/jieba/NativeJiebaAndroidHelperSpec.java +38 -0
- package/android/generated/java/com/jieba/NativeJiebaSpec.java +74 -0
- package/android/generated/jni/CMakeLists.txt +28 -0
- package/android/generated/jni/JiebaSpec-generated.cpp +98 -0
- package/android/generated/jni/JiebaSpec.h +39 -0
- package/android/generated/jni/react/renderer/components/JiebaSpec/JiebaSpecJSI.h +144 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/jieba/JiebaAndroidHelperModule.kt +48 -0
- package/android/src/main/java/com/jieba/JiebaPackage.kt +32 -0
- package/cpp/JiebaImpl.cpp +154 -0
- package/cpp/JiebaImpl.h +37 -0
- package/cpp/cppjieba/LICENSE +20 -0
- package/cpp/cppjieba/deps/limonp/LICENSE +20 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/ArgvContext.hpp +70 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/Closure.hpp +206 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/Colors.hpp +31 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/Condition.hpp +38 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/Config.hpp +103 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/ForcePublic.hpp +7 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/LocalVector.hpp +139 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/Logging.hpp +92 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/NonCopyable.hpp +21 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/StdExtension.hpp +157 -0
- package/cpp/cppjieba/deps/limonp/include/limonp/StringUtil.hpp +386 -0
- package/cpp/cppjieba/dict/hmm_model.utf8 +34 -0
- package/cpp/cppjieba/dict/idf.utf8 +258826 -0
- package/cpp/cppjieba/dict/jieba.dict.utf8 +348982 -0
- package/cpp/cppjieba/dict/stop_words.utf8 +1534 -0
- package/cpp/cppjieba/dict/user.dict.utf8 +3 -0
- package/cpp/cppjieba/include/cppjieba/DictTrie.hpp +322 -0
- package/cpp/cppjieba/include/cppjieba/FullSegment.hpp +94 -0
- package/cpp/cppjieba/include/cppjieba/HMMModel.hpp +131 -0
- package/cpp/cppjieba/include/cppjieba/HMMSegment.hpp +211 -0
- package/cpp/cppjieba/include/cppjieba/Jieba.hpp +169 -0
- package/cpp/cppjieba/include/cppjieba/KeywordExtractor.hpp +152 -0
- package/cpp/cppjieba/include/cppjieba/MPSegment.hpp +137 -0
- package/cpp/cppjieba/include/cppjieba/MixSegment.hpp +109 -0
- package/cpp/cppjieba/include/cppjieba/PosTagger.hpp +77 -0
- package/cpp/cppjieba/include/cppjieba/PreFilter.hpp +54 -0
- package/cpp/cppjieba/include/cppjieba/QuerySegment.hpp +89 -0
- package/cpp/cppjieba/include/cppjieba/SegmentBase.hpp +46 -0
- package/cpp/cppjieba/include/cppjieba/SegmentTagged.hpp +23 -0
- package/cpp/cppjieba/include/cppjieba/TextRankExtractor.hpp +192 -0
- package/cpp/cppjieba/include/cppjieba/Trie.hpp +200 -0
- package/cpp/cppjieba/include/cppjieba/Unicode.hpp +231 -0
- package/cpp/cppjieba/include/cppjieba/UnicodeFile.hpp +68 -0
- package/ios/OnLoad.mm +35 -0
- package/ios/generated/ReactCodegen/JiebaSpec/JiebaSpec-generated.mm +126 -0
- package/ios/generated/ReactCodegen/JiebaSpec/JiebaSpec.h +103 -0
- package/ios/generated/ReactCodegen/JiebaSpecJSI.h +144 -0
- package/lib/module/NativeJieba.js +5 -0
- package/lib/module/NativeJieba.js.map +1 -0
- package/lib/module/NativeJiebaAndroidHelper.js +5 -0
- package/lib/module/NativeJiebaAndroidHelper.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/init.js +24 -0
- package/lib/module/init.js.map +1 -0
- package/lib/module/jieba.js +31 -0
- package/lib/module/jieba.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeJieba.d.ts +22 -0
- package/lib/typescript/src/NativeJieba.d.ts.map +1 -0
- package/lib/typescript/src/NativeJiebaAndroidHelper.d.ts +7 -0
- package/lib/typescript/src/NativeJiebaAndroidHelper.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/init.d.ts +2 -0
- package/lib/typescript/src/init.d.ts.map +1 -0
- package/lib/typescript/src/jieba.d.ts +18 -0
- package/lib/typescript/src/jieba.d.ts.map +1 -0
- package/package.json +197 -0
- package/react-native.config.js +17 -0
- package/src/NativeJieba.ts +19 -0
- package/src/NativeJiebaAndroidHelper.ts +7 -0
- package/src/index.tsx +13 -0
- package/src/init.ts +25 -0
- package/src/jieba.ts +43 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#ifndef CPPJIEBA_DICT_TRIE_HPP
|
|
2
|
+
#define CPPJIEBA_DICT_TRIE_HPP
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <fstream>
|
|
6
|
+
#include <cstring>
|
|
7
|
+
#include <cstdlib>
|
|
8
|
+
#include <cmath>
|
|
9
|
+
#include <deque>
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
#include <set>
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <unordered_map>
|
|
15
|
+
#include <unordered_set>
|
|
16
|
+
#include "limonp/StringUtil.hpp"
|
|
17
|
+
#include "limonp/Logging.hpp"
|
|
18
|
+
#include "UnicodeFile.hpp"
|
|
19
|
+
#include "Unicode.hpp"
|
|
20
|
+
#include "Trie.hpp"
|
|
21
|
+
|
|
22
|
+
namespace cppjieba {
|
|
23
|
+
|
|
24
|
+
const double MIN_DOUBLE = -3.14e+100;
|
|
25
|
+
const double MAX_DOUBLE = 3.14e+100;
|
|
26
|
+
const size_t DICT_COLUMN_NUM = 3;
|
|
27
|
+
const char* const UNKNOWN_TAG = "";
|
|
28
|
+
|
|
29
|
+
class DictTrie {
|
|
30
|
+
public:
|
|
31
|
+
enum UserWordWeightOption {
|
|
32
|
+
WordWeightMin,
|
|
33
|
+
WordWeightMedian,
|
|
34
|
+
WordWeightMax,
|
|
35
|
+
}; // enum UserWordWeightOption
|
|
36
|
+
|
|
37
|
+
DictTrie(const std::string& dict_path, const std::string& user_dict_paths = "", UserWordWeightOption user_word_weight_opt = WordWeightMedian) {
|
|
38
|
+
Init(dict_path, user_dict_paths, user_word_weight_opt);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
~DictTrie() {
|
|
42
|
+
delete trie_;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
bool InsertUserWord(const std::string& word, const std::string& tag = UNKNOWN_TAG) {
|
|
46
|
+
DictUnit node_info;
|
|
47
|
+
if (!MakeNodeInfo(node_info, word, user_word_default_weight_, tag)) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
active_node_infos_.push_back(node_info);
|
|
51
|
+
trie_->InsertNode(node_info.word, &active_node_infos_.back());
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
bool InsertUserWord(const std::string& word,int freq, const std::string& tag = UNKNOWN_TAG) {
|
|
56
|
+
DictUnit node_info;
|
|
57
|
+
double weight = freq ? log(1.0 * freq / freq_sum_) : user_word_default_weight_ ;
|
|
58
|
+
if (!MakeNodeInfo(node_info, word, weight , tag)) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
active_node_infos_.push_back(node_info);
|
|
62
|
+
trie_->InsertNode(node_info.word, &active_node_infos_.back());
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
bool DeleteUserWord(const std::string& word, const std::string& tag = UNKNOWN_TAG) {
|
|
67
|
+
DictUnit node_info;
|
|
68
|
+
if (!MakeNodeInfo(node_info, word, user_word_default_weight_, tag)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
trie_->DeleteNode(node_info.word, &node_info);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const DictUnit* Find(RuneStrArray::const_iterator begin, RuneStrArray::const_iterator end) const {
|
|
76
|
+
return trie_->Find(begin, end);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void Find(RuneStrArray::const_iterator begin,
|
|
80
|
+
RuneStrArray::const_iterator end,
|
|
81
|
+
std::vector<struct Dag>&res,
|
|
82
|
+
size_t max_word_len = MAX_WORD_LENGTH) const {
|
|
83
|
+
trie_->Find(begin, end, res, max_word_len);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
bool Find(const std::string& word)
|
|
87
|
+
{
|
|
88
|
+
const DictUnit *tmp = NULL;
|
|
89
|
+
RuneStrArray runes;
|
|
90
|
+
if (!DecodeUTF8RunesInString(word, runes))
|
|
91
|
+
{
|
|
92
|
+
XLOG(ERROR) << "Decode failed.";
|
|
93
|
+
}
|
|
94
|
+
tmp = Find(runes.begin(), runes.end());
|
|
95
|
+
if (tmp == NULL)
|
|
96
|
+
{
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
else
|
|
100
|
+
{
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
bool IsUserDictSingleChineseWord(const Rune& word) const {
|
|
106
|
+
return IsIn(user_dict_single_chinese_word_, word);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
double GetMinWeight() const {
|
|
110
|
+
return min_weight_;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
void InserUserDictNode(const std::string& line) {
|
|
114
|
+
std::vector<std::string> buf;
|
|
115
|
+
DictUnit node_info;
|
|
116
|
+
limonp::Split(line, buf, " ");
|
|
117
|
+
if(buf.size() == 1){
|
|
118
|
+
MakeNodeInfo(node_info,
|
|
119
|
+
buf[0],
|
|
120
|
+
user_word_default_weight_,
|
|
121
|
+
UNKNOWN_TAG);
|
|
122
|
+
} else if (buf.size() == 2) {
|
|
123
|
+
MakeNodeInfo(node_info,
|
|
124
|
+
buf[0],
|
|
125
|
+
user_word_default_weight_,
|
|
126
|
+
buf[1]);
|
|
127
|
+
} else if (buf.size() == 3) {
|
|
128
|
+
int freq = atoi(buf[1].c_str());
|
|
129
|
+
assert(freq_sum_ > 0.0);
|
|
130
|
+
double weight = log(1.0 * freq / freq_sum_);
|
|
131
|
+
MakeNodeInfo(node_info, buf[0], weight, buf[2]);
|
|
132
|
+
}
|
|
133
|
+
static_node_infos_.push_back(node_info);
|
|
134
|
+
if (node_info.word.size() == 1) {
|
|
135
|
+
user_dict_single_chinese_word_.insert(node_info.word[0]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
void LoadUserDict(const std::vector<std::string>& buf) {
|
|
140
|
+
for (size_t i = 0; i < buf.size(); i++) {
|
|
141
|
+
InserUserDictNode(buf[i]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
void LoadUserDict(const std::set<std::string>& buf) {
|
|
146
|
+
std::set<std::string>::const_iterator iter;
|
|
147
|
+
for (iter = buf.begin(); iter != buf.end(); iter++){
|
|
148
|
+
InserUserDictNode(*iter);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
void LoadUserDict(const std::string& filePaths) {
|
|
153
|
+
std::vector<std::string> files = limonp::Split(filePaths, "|;");
|
|
154
|
+
for (size_t i = 0; i < files.size(); i++) {
|
|
155
|
+
std::ifstream ifs;
|
|
156
|
+
OpenInputFile(ifs, files[i]);
|
|
157
|
+
XCHECK(ifs.is_open()) << "open " << files[i] << " failed";
|
|
158
|
+
std::string line;
|
|
159
|
+
|
|
160
|
+
while(getline(ifs, line)) {
|
|
161
|
+
if (line.size() == 0) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
InserUserDictNode(line);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
private:
|
|
171
|
+
struct DictCacheEntry {
|
|
172
|
+
std::shared_ptr<const std::vector<DictUnit> > node_infos;
|
|
173
|
+
double freq_sum;
|
|
174
|
+
double min_weight;
|
|
175
|
+
double max_weight;
|
|
176
|
+
double median_weight;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
void Init(const std::string& dict_path, const std::string& user_dict_paths, UserWordWeightOption user_word_weight_opt) {
|
|
180
|
+
const DictCacheEntry& cache = GetDictCache(dict_path);
|
|
181
|
+
base_static_node_infos_ = cache.node_infos;
|
|
182
|
+
freq_sum_ = cache.freq_sum;
|
|
183
|
+
min_weight_ = cache.min_weight;
|
|
184
|
+
max_weight_ = cache.max_weight;
|
|
185
|
+
median_weight_ = cache.median_weight;
|
|
186
|
+
switch (user_word_weight_opt) {
|
|
187
|
+
case WordWeightMin:
|
|
188
|
+
user_word_default_weight_ = min_weight_;
|
|
189
|
+
break;
|
|
190
|
+
case WordWeightMedian:
|
|
191
|
+
user_word_default_weight_ = median_weight_;
|
|
192
|
+
break;
|
|
193
|
+
default:
|
|
194
|
+
user_word_default_weight_ = max_weight_;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (user_dict_paths.size()) {
|
|
199
|
+
LoadUserDict(user_dict_paths);
|
|
200
|
+
}
|
|
201
|
+
Shrink(static_node_infos_);
|
|
202
|
+
CreateTrie();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
void CreateTrie() {
|
|
206
|
+
const size_t total_size = base_static_node_infos_->size() + static_node_infos_.size();
|
|
207
|
+
assert(total_size);
|
|
208
|
+
std::vector<Unicode> words;
|
|
209
|
+
std::vector<const DictUnit*> valuePointers;
|
|
210
|
+
words.reserve(total_size);
|
|
211
|
+
valuePointers.reserve(total_size);
|
|
212
|
+
|
|
213
|
+
for (size_t i = 0; i < base_static_node_infos_->size(); i++) {
|
|
214
|
+
words.push_back((*base_static_node_infos_)[i].word);
|
|
215
|
+
valuePointers.push_back(&(*base_static_node_infos_)[i]);
|
|
216
|
+
}
|
|
217
|
+
for (size_t i = 0; i < static_node_infos_.size(); i++) {
|
|
218
|
+
words.push_back(static_node_infos_[i].word);
|
|
219
|
+
valuePointers.push_back(&static_node_infos_[i]);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
trie_ = new Trie(words, valuePointers);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
bool MakeNodeInfo(DictUnit& node_info,
|
|
226
|
+
const std::string& word,
|
|
227
|
+
double weight,
|
|
228
|
+
const std::string& tag) {
|
|
229
|
+
if (!DecodeUTF8RunesInString(word, node_info.word)) {
|
|
230
|
+
XLOG(ERROR) << "UTF-8 decode failed for dict word: " << word;
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
node_info.weight = weight;
|
|
234
|
+
node_info.tag = tag;
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static DictCacheEntry BuildDictCacheEntry(const std::string& filePath) {
|
|
239
|
+
DictCacheEntry entry;
|
|
240
|
+
std::vector<DictUnit> node_infos;
|
|
241
|
+
std::ifstream ifs;
|
|
242
|
+
OpenInputFile(ifs, filePath);
|
|
243
|
+
XCHECK(ifs.is_open()) << "open " << filePath << " failed.";
|
|
244
|
+
std::string line;
|
|
245
|
+
std::vector<std::string> buf;
|
|
246
|
+
while (getline(ifs, line)) {
|
|
247
|
+
limonp::Split(line, buf, " ");
|
|
248
|
+
XCHECK(buf.size() == DICT_COLUMN_NUM) << "split result illegal, line:" << line;
|
|
249
|
+
DictUnit node_info;
|
|
250
|
+
XCHECK(DecodeUTF8RunesInString(buf[0], node_info.word)) << "UTF-8 decode failed for dict word: " << buf[0];
|
|
251
|
+
node_info.weight = atof(buf[1].c_str());
|
|
252
|
+
node_info.tag = buf[2];
|
|
253
|
+
node_infos.push_back(node_info);
|
|
254
|
+
}
|
|
255
|
+
XCHECK(!node_infos.empty()) << "dict file is empty: " << filePath;
|
|
256
|
+
|
|
257
|
+
entry.freq_sum = CalcFreqSum(node_infos);
|
|
258
|
+
CalculateWeight(node_infos, entry.freq_sum);
|
|
259
|
+
std::vector<DictUnit> sorted = node_infos;
|
|
260
|
+
std::sort(sorted.begin(), sorted.end(), WeightCompare);
|
|
261
|
+
entry.min_weight = sorted.front().weight;
|
|
262
|
+
entry.max_weight = sorted.back().weight;
|
|
263
|
+
entry.median_weight = sorted[sorted.size() / 2].weight;
|
|
264
|
+
|
|
265
|
+
entry.node_infos = std::shared_ptr<const std::vector<DictUnit> >(new std::vector<DictUnit>(node_infos));
|
|
266
|
+
return entry;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static const DictCacheEntry& GetDictCache(const std::string& filePath) {
|
|
270
|
+
static std::unordered_map<std::string, DictCacheEntry> cache;
|
|
271
|
+
static std::mutex cache_mutex;
|
|
272
|
+
std::lock_guard<std::mutex> lock(cache_mutex);
|
|
273
|
+
std::unordered_map<std::string, DictCacheEntry>::const_iterator it = cache.find(filePath);
|
|
274
|
+
if (it != cache.end()) {
|
|
275
|
+
return it->second;
|
|
276
|
+
}
|
|
277
|
+
DictCacheEntry entry = BuildDictCacheEntry(filePath);
|
|
278
|
+
std::pair<std::unordered_map<std::string, DictCacheEntry>::iterator, bool> result =
|
|
279
|
+
cache.insert(std::make_pair(filePath, entry));
|
|
280
|
+
return result.first->second;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
static bool WeightCompare(const DictUnit& lhs, const DictUnit& rhs) {
|
|
284
|
+
return lhs.weight < rhs.weight;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static double CalcFreqSum(const std::vector<DictUnit>& node_infos) {
|
|
288
|
+
double sum = 0.0;
|
|
289
|
+
for (size_t i = 0; i < node_infos.size(); i++) {
|
|
290
|
+
sum += node_infos[i].weight;
|
|
291
|
+
}
|
|
292
|
+
return sum;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
static void CalculateWeight(std::vector<DictUnit>& node_infos, double sum) {
|
|
296
|
+
assert(sum > 0.0);
|
|
297
|
+
for (size_t i = 0; i < node_infos.size(); i++) {
|
|
298
|
+
DictUnit& node_info = node_infos[i];
|
|
299
|
+
assert(node_info.weight > 0.0);
|
|
300
|
+
node_info.weight = log(double(node_info.weight)/sum);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
void Shrink(std::vector<DictUnit>& units) const {
|
|
305
|
+
std::vector<DictUnit>(units.begin(), units.end()).swap(units);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
std::shared_ptr<const std::vector<DictUnit> > base_static_node_infos_;
|
|
309
|
+
std::vector<DictUnit> static_node_infos_;
|
|
310
|
+
std::deque<DictUnit> active_node_infos_; // must not be std::vector
|
|
311
|
+
Trie * trie_;
|
|
312
|
+
|
|
313
|
+
double freq_sum_;
|
|
314
|
+
double min_weight_;
|
|
315
|
+
double max_weight_;
|
|
316
|
+
double median_weight_;
|
|
317
|
+
double user_word_default_weight_;
|
|
318
|
+
std::unordered_set<Rune> user_dict_single_chinese_word_;
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
#endif
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#ifndef CPPJIEBA_FULLSEGMENT_H
|
|
2
|
+
#define CPPJIEBA_FULLSEGMENT_H
|
|
3
|
+
|
|
4
|
+
#include <algorithm>
|
|
5
|
+
#include <set>
|
|
6
|
+
#include <cassert>
|
|
7
|
+
#include "limonp/Logging.hpp"
|
|
8
|
+
#include "DictTrie.hpp"
|
|
9
|
+
#include "SegmentBase.hpp"
|
|
10
|
+
#include "Unicode.hpp"
|
|
11
|
+
|
|
12
|
+
namespace cppjieba {
|
|
13
|
+
class FullSegment: public SegmentBase {
|
|
14
|
+
public:
|
|
15
|
+
FullSegment(const string& dictPath) {
|
|
16
|
+
dictTrie_ = new DictTrie(dictPath);
|
|
17
|
+
isNeedDestroy_ = true;
|
|
18
|
+
}
|
|
19
|
+
FullSegment(const DictTrie* dictTrie)
|
|
20
|
+
: dictTrie_(dictTrie), isNeedDestroy_(false) {
|
|
21
|
+
assert(dictTrie_);
|
|
22
|
+
}
|
|
23
|
+
~FullSegment() {
|
|
24
|
+
if (isNeedDestroy_) {
|
|
25
|
+
delete dictTrie_;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
void Cut(const string& sentence,
|
|
29
|
+
vector<string>& words) const {
|
|
30
|
+
vector<Word> tmp;
|
|
31
|
+
Cut(sentence, tmp);
|
|
32
|
+
GetStringsFromWords(tmp, words);
|
|
33
|
+
}
|
|
34
|
+
void Cut(const string& sentence,
|
|
35
|
+
vector<Word>& words) const {
|
|
36
|
+
PreFilter pre_filter(symbols_, sentence);
|
|
37
|
+
PreFilter::Range range;
|
|
38
|
+
vector<WordRange> wrs;
|
|
39
|
+
wrs.reserve(sentence.size()/2);
|
|
40
|
+
while (pre_filter.HasNext()) {
|
|
41
|
+
range = pre_filter.Next();
|
|
42
|
+
Cut(range.begin, range.end, wrs);
|
|
43
|
+
}
|
|
44
|
+
words.clear();
|
|
45
|
+
words.reserve(wrs.size());
|
|
46
|
+
GetWordsFromWordRanges(sentence, wrs, words);
|
|
47
|
+
}
|
|
48
|
+
void Cut(RuneStrArray::const_iterator begin,
|
|
49
|
+
RuneStrArray::const_iterator end,
|
|
50
|
+
vector<WordRange>& res) const {
|
|
51
|
+
// result of searching in trie tree
|
|
52
|
+
LocalVector<pair<size_t, const DictUnit*> > tRes;
|
|
53
|
+
|
|
54
|
+
// max index of res's words
|
|
55
|
+
size_t maxIdx = 0;
|
|
56
|
+
|
|
57
|
+
// always equals to (uItr - begin)
|
|
58
|
+
size_t uIdx = 0;
|
|
59
|
+
|
|
60
|
+
// tmp variables
|
|
61
|
+
size_t wordLen = 0;
|
|
62
|
+
assert(dictTrie_);
|
|
63
|
+
vector<struct Dag> dags;
|
|
64
|
+
dictTrie_->Find(begin, end, dags);
|
|
65
|
+
for (size_t i = 0; i < dags.size(); i++) {
|
|
66
|
+
for (size_t j = 0; j < dags[i].nexts.size(); j++) {
|
|
67
|
+
size_t nextoffset = dags[i].nexts[j].first;
|
|
68
|
+
assert(nextoffset < dags.size());
|
|
69
|
+
const DictUnit* du = dags[i].nexts[j].second;
|
|
70
|
+
if (du == NULL) {
|
|
71
|
+
wordLen = 1;
|
|
72
|
+
if (dags[i].nexts.size() == 1 && maxIdx <= uIdx) {
|
|
73
|
+
WordRange wr(begin + i, begin + nextoffset);
|
|
74
|
+
res.push_back(wr);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
wordLen = du->word.size();
|
|
78
|
+
if (wordLen >= 2 || (dags[i].nexts.size() == 1 && maxIdx <= uIdx)) {
|
|
79
|
+
WordRange wr(begin + i, begin + nextoffset);
|
|
80
|
+
res.push_back(wr);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
maxIdx = uIdx + wordLen > maxIdx ? uIdx + wordLen : maxIdx;
|
|
84
|
+
}
|
|
85
|
+
uIdx++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
private:
|
|
89
|
+
const DictTrie* dictTrie_;
|
|
90
|
+
bool isNeedDestroy_;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#endif
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#ifndef CPPJIEBA_HMMMODEL_H
|
|
2
|
+
#define CPPJIEBA_HMMMODEL_H
|
|
3
|
+
|
|
4
|
+
#include "UnicodeFile.hpp"
|
|
5
|
+
#include "limonp/StringUtil.hpp"
|
|
6
|
+
#include "Trie.hpp"
|
|
7
|
+
|
|
8
|
+
namespace cppjieba {
|
|
9
|
+
|
|
10
|
+
using namespace limonp;
|
|
11
|
+
typedef unordered_map<Rune, double> EmitProbMap;
|
|
12
|
+
|
|
13
|
+
struct HMMModel {
|
|
14
|
+
/*
|
|
15
|
+
* STATUS:
|
|
16
|
+
* 0: HMMModel::B, 1: HMMModel::E, 2: HMMModel::M, 3:HMMModel::S
|
|
17
|
+
* */
|
|
18
|
+
enum {B = 0, E = 1, M = 2, S = 3, STATUS_SUM = 4};
|
|
19
|
+
|
|
20
|
+
HMMModel(const string& modelPath) {
|
|
21
|
+
memset(startProb, 0, sizeof(startProb));
|
|
22
|
+
memset(transProb, 0, sizeof(transProb));
|
|
23
|
+
statMap[0] = 'B';
|
|
24
|
+
statMap[1] = 'E';
|
|
25
|
+
statMap[2] = 'M';
|
|
26
|
+
statMap[3] = 'S';
|
|
27
|
+
emitProbVec.push_back(&emitProbB);
|
|
28
|
+
emitProbVec.push_back(&emitProbE);
|
|
29
|
+
emitProbVec.push_back(&emitProbM);
|
|
30
|
+
emitProbVec.push_back(&emitProbS);
|
|
31
|
+
LoadModel(modelPath);
|
|
32
|
+
}
|
|
33
|
+
~HMMModel() {
|
|
34
|
+
}
|
|
35
|
+
void LoadModel(const string& filePath) {
|
|
36
|
+
ifstream ifile;
|
|
37
|
+
OpenInputFile(ifile, filePath);
|
|
38
|
+
XCHECK(ifile.is_open()) << "open " << filePath << " failed";
|
|
39
|
+
string line;
|
|
40
|
+
vector<string> tmp;
|
|
41
|
+
vector<string> tmp2;
|
|
42
|
+
//Load startProb
|
|
43
|
+
XCHECK(GetLine(ifile, line));
|
|
44
|
+
Split(line, tmp, " ");
|
|
45
|
+
XCHECK(tmp.size() == STATUS_SUM);
|
|
46
|
+
for (size_t j = 0; j< tmp.size(); j++) {
|
|
47
|
+
startProb[j] = atof(tmp[j].c_str());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//Load transProb
|
|
51
|
+
for (size_t i = 0; i < STATUS_SUM; i++) {
|
|
52
|
+
XCHECK(GetLine(ifile, line));
|
|
53
|
+
Split(line, tmp, " ");
|
|
54
|
+
XCHECK(tmp.size() == STATUS_SUM);
|
|
55
|
+
for (size_t j =0; j < STATUS_SUM; j++) {
|
|
56
|
+
transProb[i][j] = atof(tmp[j].c_str());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//Load emitProbB
|
|
61
|
+
XCHECK(GetLine(ifile, line));
|
|
62
|
+
XCHECK(LoadEmitProb(line, emitProbB));
|
|
63
|
+
|
|
64
|
+
//Load emitProbE
|
|
65
|
+
XCHECK(GetLine(ifile, line));
|
|
66
|
+
XCHECK(LoadEmitProb(line, emitProbE));
|
|
67
|
+
|
|
68
|
+
//Load emitProbM
|
|
69
|
+
XCHECK(GetLine(ifile, line));
|
|
70
|
+
XCHECK(LoadEmitProb(line, emitProbM));
|
|
71
|
+
|
|
72
|
+
//Load emitProbS
|
|
73
|
+
XCHECK(GetLine(ifile, line));
|
|
74
|
+
XCHECK(LoadEmitProb(line, emitProbS));
|
|
75
|
+
}
|
|
76
|
+
double GetEmitProb(const EmitProbMap* ptMp, Rune key,
|
|
77
|
+
double defVal)const {
|
|
78
|
+
EmitProbMap::const_iterator cit = ptMp->find(key);
|
|
79
|
+
if (cit == ptMp->end()) {
|
|
80
|
+
return defVal;
|
|
81
|
+
}
|
|
82
|
+
return cit->second;
|
|
83
|
+
}
|
|
84
|
+
bool GetLine(ifstream& ifile, string& line) {
|
|
85
|
+
while (getline(ifile, line)) {
|
|
86
|
+
Trim(line);
|
|
87
|
+
if (line.empty()) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (StartsWith(line, "#")) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
bool LoadEmitProb(const string& line, EmitProbMap& mp) {
|
|
98
|
+
if (line.empty()) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
vector<string> tmp, tmp2;
|
|
102
|
+
Unicode unicode;
|
|
103
|
+
Split(line, tmp, ",");
|
|
104
|
+
for (size_t i = 0; i < tmp.size(); i++) {
|
|
105
|
+
Split(tmp[i], tmp2, ":");
|
|
106
|
+
if (2 != tmp2.size()) {
|
|
107
|
+
XLOG(ERROR) << "emitProb illegal.";
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
if (!DecodeUTF8RunesInString(tmp2[0], unicode) || unicode.size() != 1) {
|
|
111
|
+
XLOG(ERROR) << "TransCode failed.";
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
mp[unicode[0]] = atof(tmp2[1].c_str());
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
char statMap[STATUS_SUM];
|
|
120
|
+
double startProb[STATUS_SUM];
|
|
121
|
+
double transProb[STATUS_SUM][STATUS_SUM];
|
|
122
|
+
EmitProbMap emitProbB;
|
|
123
|
+
EmitProbMap emitProbE;
|
|
124
|
+
EmitProbMap emitProbM;
|
|
125
|
+
EmitProbMap emitProbS;
|
|
126
|
+
vector<EmitProbMap* > emitProbVec;
|
|
127
|
+
}; // struct HMMModel
|
|
128
|
+
|
|
129
|
+
} // namespace cppjieba
|
|
130
|
+
|
|
131
|
+
#endif
|