增加两条词性标注的规则,针对连续英文和数字。

This commit is contained in:
wyy 2014-11-29 12:45:11 +08:00
parent 9d5359fc34
commit e9cbec02c2
8 changed files with 101 additions and 25 deletions

View File

@ -5,6 +5,7 @@
1. 修改两条更细粒度的特殊过滤规则,将连续的数字(包括浮点数)和连续的字母单独切分出来(而不会混在一起)。 1. 修改两条更细粒度的特殊过滤规则,将连续的数字(包括浮点数)和连续的字母单独切分出来(而不会混在一起)。
2. 修改最大概率法时动态规划过程需要使用的 DAG 数据结构(同时也修改 Trie 的 DAG 查询函数),提高分词速度 8% 。 2. 修改最大概率法时动态规划过程需要使用的 DAG 数据结构(同时也修改 Trie 的 DAG 查询函数),提高分词速度 8% 。
3. 使用了 `Aho-Corasick-Automation` 算法提速 Trie 查找的过程等优化,提升性能。 3. 使用了 `Aho-Corasick-Automation` 算法提速 Trie 查找的过程等优化,提升性能。
4. 增加词性标注的两条特殊规则。
## v2.4.3 ## v2.4.3

View File

@ -9,7 +9,7 @@ CppJieba是"结巴"中文分词的C++版本
## 特性 ## 特性
+ 源代码都写进头文件`src/*.hpp`里,`include`即可使用。 + 源代码都写进头文件`src/*.hpp`里,`include`即可使用。
+ 支持`utf-8, gbk`编码,但是推荐使用`utf-8`编码。 + 支持`utf-8, gbk`编码,但是推荐使用`utf-8`编码 因为`gbk`编码缺少严格测试,慎用
+ 内置分词服务`server/server.cpp`在linux环境下可安装使用。 + 内置分词服务`server/server.cpp`在linux环境下可安装使用。
+ 项目自带较为完善的单元测试,核心功能中文分词(utf8)的稳定性接受过线上环境检验。 + 项目自带较为完善的单元测试,核心功能中文分词(utf8)的稳定性接受过线上环境检验。
+ 支持载自定义用户词典。 + 支持载自定义用户词典。
@ -268,7 +268,7 @@ make && ./keyword.demo
详情请看 `test/tagging_demo.cpp`. 详情请看 `test/tagging_demo.cpp`.
``` ```
["我:r", "是:v", "蓝翔:x", "技工:n", "拖拉机:n", "学院:n", "手扶拖拉机:n", "专业:n", "的:uj", "。:x", "不用:v", "多久:m", ":x", "我:r", "就:d", "会:v", "升职:v", "加薪:nr", ":x", "当:t", "上:f", "总经理:n", ":x", "出任:v", "CEO:x", ":x", "迎娶:v", "白富美:x", ":x", "走上:v", "人生:n", "巅峰:n", "。:x"] ["我:r", "是:v", "蓝翔:x", "技工:n", "拖拉机:n", "学院:n", "手扶拖拉机:n", "专业:n", "的:uj", "。:x", "不用:v", "多久:m", ":x", "我:r", "就:d", "会:v", "升职:v", "加薪:nr", ":x", "当:t", "上:f", "总经理:n", ":x", "出任:v", "CEO:eng", ":x", "迎娶:v", "白富美:x", ":x", "走上:v", "人生:n", "巅峰:n", "。:x"]
``` ```
支持自定义词性。 支持自定义词性。
@ -281,10 +281,10 @@ make && ./keyword.demo
结果如下: 结果如下:
``` ```
["我:r", "是:v", "蓝翔:nz", "技工:n", "拖拉机:n", "学院:n", "手扶拖拉机:n", "专业:n", "的:uj", "。:x", "不用:v", "多久:m", ":x", "我:r", "就:d", "会:v", "升职:v", "加薪:nr", ":x", "当:t", "上:f", "总经理:n", ":x", "出任:v", "CEO:x", ":x", "迎娶:v", "白富美:x", ":x", "走上:v", "人生:n", "巅峰:n", "。:x"] ["我:r", "是:v", "蓝翔:nz", "技工:n", "拖拉机:n", "学院:n", "手扶拖拉机:n", "专业:n", "的:uj", "。:x", "不用:v", "多久:m", ":x", "我:r", "就:d", "会:v", "升职:v", "加薪:nr", ":x", "当:t", "上:f", "总经理:n", ":x", "出任:v", "CEO:eng", ":x", "迎娶:v", "白富美:x", ":x", "走上:v", "人生:n", "巅峰:n", "。:x"]
``` ```
## 词典资料 ## 其它词典资料分享
+ [dict.367W.utf8.tar.gz] iLife(`562193561@qq.com`) + [dict.367W.utf8.tar.gz] iLife(`562193561@qq.com`)

View File

@ -21,7 +21,7 @@ namespace CppJieba
const double MIN_DOUBLE = -3.14e+100; const double MIN_DOUBLE = -3.14e+100;
const double MAX_DOUBLE = 3.14e+100; const double MAX_DOUBLE = 3.14e+100;
const size_t DICT_COLUMN_NUM = 3; const size_t DICT_COLUMN_NUM = 3;
const char* const UNKNOWN_TAG = "x"; const char* const UNKNOWN_TAG = "";
class DictTrie class DictTrie
{ {

View File

@ -9,6 +9,10 @@ namespace CppJieba
{ {
using namespace Limonp; using namespace Limonp;
static const char* const POS_M = "m";
static const char* const POS_ENG = "eng";
static const char* const POS_X = "x";
class PosTagger class PosTagger
{ {
private: private:
@ -39,6 +43,7 @@ namespace CppJieba
LIMONP_CHECK(_dictTrie); LIMONP_CHECK(_dictTrie);
}; };
bool tag(const string& src, vector<pair<string, string> >& res) const bool tag(const string& src, vector<pair<string, string> >& res) const
{ {
vector<string> cutRes; vector<string> cutRes;
@ -58,11 +63,46 @@ namespace CppJieba
return false; return false;
} }
tmp = _dictTrie->find(unico.begin(), unico.end()); tmp = _dictTrie->find(unico.begin(), unico.end());
res.push_back(make_pair(*itr, tmp == NULL ? "x" : tmp->tag)); if(tmp == NULL || tmp->tag.empty())
{
res.push_back(make_pair(*itr, _specialRule(unico)));
}
else
{
res.push_back(make_pair(*itr, tmp->tag));
}
} }
tmp = NULL;
return !res.empty(); return !res.empty();
} }
private:
const char* _specialRule(const Unicode& unicode) const
{
size_t m = 0;
size_t eng = 0;
for(size_t i = 0; i < unicode.size() && eng < unicode.size() / 2; i++)
{
if(unicode[i] < 0x80)
{
eng ++;
if('0' <= unicode[i] && unicode[i] <= '9')
{
m++;
}
}
}
// ascii char is not found
if(eng == 0)
{
return POS_X;
}
// all the ascii is number char
if(m == eng)
{
return POS_M;
}
// the ascii chars contain english letter
return POS_ENG;
}
}; };
} }

View File

@ -39,6 +39,24 @@ namespace CppJieba
{ {
return encode(uni.begin(), uni.end(), res); return encode(uni.begin(), uni.end(), res);
} }
// compiler is expected to optimized this function to avoid return value copy
inline string encode(Unicode::const_iterator begin, Unicode::const_iterator end)
{
string res;
res.reserve(end - begin);
encode(begin, end, res);
return res;
}
// compiler is expected to optimized this function to avoid return value copy
inline Unicode decode(const string& str)
{
Unicode unicode;
unicode.reserve(str.size());
decode(str, unicode);
return unicode;
}
} }
} }

View File

@ -2,3 +2,5 @@
韩玉鉴赏 韩玉鉴赏
A A
B B
iphone6
蓝翔 nz

View File

@ -3,26 +3,41 @@
using namespace CppJieba; using namespace CppJieba;
const char * const QUERY_TEST1 = "我是蓝翔技工拖拉机学院手扶拖拉机专业的。不用多久我就会升职加薪当上总经理出任CEO迎娶白富美走上人生巅峰。"; static const char * const QUERY_TEST1 = "我是蓝翔技工拖拉机学院手扶拖拉机专业的。不用多久我就会升职加薪当上总经理出任CEO迎娶白富美走上人生巅峰。";
const char * const ANS_TEST1 = "[\"我:r\", \"是:v\", \"蓝翔:x\", \"技工:n\", \"拖拉机:n\", \"学院:n\", \"手扶拖拉机:n\", \"专业:n\", \"的:uj\", \"。:x\", \"不用:v\", \"多久:m\", \":x\", \"我:r\", \"就:d\", \"会:v\", \"升职:v\", \"加薪:nr\", \":x\", \"当上:t\", \"总经理:n\", \":x\", \"出任:v\", \"CEO:x\", \":x\", \"迎娶:v\", \"白富:x\", \"美:ns\", \":x\", \"走上:v\", \"人生:n\", \"巅峰:n\", \"。:x\"]"; static const char * const ANS_TEST1 = "[\"我:r\", \"是:v\", \"蓝翔:x\", \"技工:n\", \"拖拉机:n\", \"学院:n\", \"手扶拖拉机:n\", \"专业:n\", \"的:uj\", \"。:x\", \"不用:v\", \"多久:m\", \":x\", \"我:r\", \"就:d\", \"会:v\", \"升职:v\", \"加薪:nr\", \":x\", \"当上:t\", \"总经理:n\", \":x\", \"出任:v\", \"CEO:eng\", \":x\", \"迎娶:v\", \"白富:x\", \"美:ns\", \":x\", \"走上:v\", \"人生:n\", \"巅峰:n\", \"。:x\"]";
const char * const QUERY_TEST2 = "我是蓝翔技工拖拉机学院手扶拖拉机专业的。不用多久我就会升职加薪当上总经理出任CEO迎娶白富美走上人生巅峰。"; static const char * const QUERY_TEST2 = "我是蓝翔技工拖拉机学院手扶拖拉机专业的。不用多久我就会升职加薪当上总经理出任CEO迎娶白富美走上人生巅峰。";
const char * const ANS_TEST2 = "[\"我:r\", \"是:v\", \"蓝翔:nz\", \"技工:n\", \"拖拉机:n\", \"学院:n\", \"手扶拖拉机:n\", \"专业:n\", \"的:uj\", \"。:x\", \"不用:v\", \"多久:m\", \":x\", \"我:r\", \"就:d\", \"会:v\", \"升职:v\", \"加薪:nr\", \":x\", \"当上:t\", \"总经理:n\", \":x\", \"出任:v\", \"CEO:x\", \":x\", \"迎娶:v\", \"白富:x\", \"美:ns\", \":x\", \"走上:v\", \"人生:n\", \"巅峰:n\", \"。:x\"]"; static const char * const ANS_TEST2 = "[\"我:r\", \"是:v\", \"蓝翔:nz\", \"技工:n\", \"拖拉机:n\", \"学院:n\", \"手扶拖拉机:n\", \"专业:n\", \"的:uj\", \"。:x\", \"不用:v\", \"多久:m\", \":x\", \"我:r\", \"就:d\", \"会:v\", \"升职:v\", \"加薪:nr\", \":x\", \"当上:t\", \"总经理:n\", \":x\", \"出任:v\", \"CEO:eng\", \":x\", \"迎娶:v\", \"白富:x\", \"美:ns\", \":x\", \"走上:v\", \"人生:n\", \"巅峰:n\", \"。:x\"]";
TEST(PosTaggerTest, Test1) static const char * const QUERY_TEST3 = "iphone6手机的最大特点是很容易弯曲。";
static const char * const ANS_TEST3 = "[\"iphone6:eng\", \"手机:n\", \"的:uj\", \"最大:a\", \"特点:n\", \"是:v\", \"很:zg\", \"容易:a\", \"弯曲:v\", \"。:x\"]";
//static const char * const ANS_TEST3 = "";
TEST(PosTaggerTest, Test)
{ {
PosTagger tagger("../dict/jieba.dict.utf8", "../dict/hmm_model.utf8"); PosTagger tagger("../dict/jieba.dict.utf8", "../dict/hmm_model.utf8");
vector<pair<string, string> > res; {
tagger.tag(QUERY_TEST1, res); vector<pair<string, string> > res;
string s; tagger.tag(QUERY_TEST1, res);
s << res; string s;
ASSERT_TRUE(s == ANS_TEST1); s << res;
ASSERT_TRUE(s == ANS_TEST1);
}
} }
TEST(PosTaggerTest, Test2) TEST(PosTagger, TestUserDict)
{ {
PosTagger tagger("../dict/jieba.dict.utf8", "../dict/hmm_model.utf8", "../dict/user.dict.utf8"); PosTagger tagger("../dict/jieba.dict.utf8", "../dict/hmm_model.utf8", "../test/testdata/userdict.utf8");
vector<pair<string, string> > res; {
tagger.tag(QUERY_TEST2, res); vector<pair<string, string> > res;
string s; tagger.tag(QUERY_TEST2, res);
s << res; string s;
ASSERT_TRUE(s == ANS_TEST2); s << res;
ASSERT_EQ(s, ANS_TEST2);
}
{
vector<pair<string, string> > res;
tagger.tag(QUERY_TEST3, res);
string s;
s << res;
ASSERT_EQ(s, ANS_TEST3);
}
} }

View File

@ -65,7 +65,7 @@ TEST(DictTrieTest, UserDict)
ASSERT_TRUE(unit); ASSERT_TRUE(unit);
string res ; string res ;
res << *unit; res << *unit;
ASSERT_EQ("[\"20113\", \"35745\", \"31639\"] x -2.975", res); ASSERT_EQ("[\"20113\", \"35745\", \"31639\"] -2.975", res);
} }
TEST(DictTrieTest, automation) TEST(DictTrieTest, automation)