1 概述
汉语自动分词是把没有明显分界标志的字串切分为词串。包括:标点符号、数字、数学符号、各种 标记、人名、地名、机构名等未登录词的识别。本篇博客使用Java编程语言实现基于规则的双向最大匹配算法,算是NLP里的一个“Hello world”了。
2 理论描述
基于规则的自动分词算法
(1) 事先人工建立好分词词典和分词规则库。
(2) 原理为基于字符串匹配进行分词,这样就要 求有足够大的词表为依据。
(3) 通过一定的算法来实现,如正向最大匹配法、 逆向最大匹配法、双向匹配法等。
(4) 缺点:当分词词典所收容的词较少时,显然覆盖度就有限,分词的正确率就低。
3 算法描述
本文实现双向最大匹配算法,具体算法描述如下:
设MaxLen表示最大词长,D为分词词典。
MM:正向最大匹配法 (Maximum Matching Method,MM)
(1) 从待切分语料中按正向取长度为MaxLen的字串subStr,令 wordLen=MaxLen;
(2) 把subStr与D中的词相匹配;
(3) 若匹配成功,则认为该字串为词,指向待切分语料的指针向前移wordLen个汉字(字节),返回到(1);
(4) 若不成功:如果wordLen>1,则将Len减1,从待切分语料中取长度为wordLen的字串subStr,返回到(2)。否则,得到长度为1的单字词,指向待切分语料的指针向前移1个汉字, 返回(1)。
/**
* 正向最大匹配算法
*
* @param source 需要进行分词的字符串
* @param wordLen 搜索的词的长度
* @param currentPos 分词进行的当前位置
*/
private void MM(String source, int wordLen, int currentPos) {
int sLength = source.length(); // 获取当前字符串长度
if (currentPos + 1 > sLength)
return; // 递归结束
while ((currentPos + wordLen) > sLength) {
wordLen = wordLen - 1; // 边界处理
}
// 获取子串
String subStr = source.substring(currentPos, currentPos + wordLen);
if (dict.contains(subStr)) {
result = result + subStr + "/ ";
currentPos = currentPos + wordLen; // 找到,搜索位置后移动
MM(source, MAX_LEN, currentPos);
} else {
if (wordLen >= 1) {
wordLen = wordLen - 1; // 当前长度找不到,搜索词的字数减小
MM(source, wordLen, currentPos);
}
}
}
RMM:逆向最大匹配法 (Reverse Maximum Matching Method,RMM)
(1) 从待切分语料中按逆向取长度为MaxLen的字串subStr,令 wordLen=MaxLen;
(2) 把subStr与D中的词相匹配;
(3) 若匹配成功,则认为该字串为词,指向待切分语料的指针向后移wordLen个汉字(字节),返回到(1);
(4) 若不成功:如果wordLen>1,则将Len减1,从待切分语料中取长度为wordLen的字串subStr,返回到(2)。否则,得到长度为1的单字词,指向待切分语料的指针向前移1个汉字, 返回(1)。
/**
* 逆向最大匹配算法
*
* @param source 需要进行分词的字符串
* @param wordLen 搜索词长度
* @param currentPos 分词进行的当前位置
*/
private void RMM(String source, int wordLen, int currentPos) {
if (currentPos < 1)
return;
if (currentPos < wordLen) {
wordLen = currentPos; // 边界处理
}
// 获取子串
String subStr = source.substring(currentPos - wordLen, currentPos);
if (dict.contains(subStr)) {
result = subStr + "/ " + result;
currentPos = currentPos - wordLen; // 找到,搜索位置前移动
RMM(source, MAX_LEN, currentPos);
} else {
if (wordLen >= 1) {
wordLen = wordLen - 1;
RMM(source, wordLen, currentPos);
}
}
}
4 详例描述
以对外经济技术合作与交流不断扩大。
为例,详细描述算法如下:
MM:(以MaxLen=4为例)
对外经济——>不匹配,wordLen-1
对外经——>不匹配,wordLen-1
对外——>找到匹配,指针移动,wordLen=4
技术合作——>不匹配,wordLen-1
…
结果:对外/ 经济/ 技术/ 合作/ 与/ 交流/ 不断/ 扩大/ 。/
RMM:(以MaxLen=4为例)
断扩大。——>不匹配,wordLen-1
扩大。——>不匹配,wordLen-1
大。——>不匹配,wordLen-1
。——>找到匹配,指针移动,wordLen=4
…
结果:对外/ 经济/ 技术/ 合作/ 与/ 交流/ 不断/ 扩大/ 。/
5 其他情况
有文章表明90%情况下正向匹配和逆向匹配的结果是相同的,当正向和逆向匹配结果不吻合时,我们可以进行人工消歧,或者使用其他启发式规则进行判断,这里不再赘述。