中文分词
0
下面是一个中文分词算法,只有片段,完整例子请在后面下载完整代码:
package com.acgist.nlp.query.analyzer;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
/**
* 分词器
* 注意词典必须有序排放
*/
public class Analyzer {
private char[] chars; // 字符串分割
private int index = 0; // 分词序号
private int matchIndex = 0; // 已经匹配的长度
private String content; // 原始句子
private boolean maximize; // 是否最大分词
private List<Token> tokens; // 分解出来的词语
public static final String REGEX_BLANK = "\\s";
public static final String REGEX_NUMBER = "[0-9]";
public static final String REGEX_LETTER = "[a-zA-Z]";
public static final String REGEX_CHINESE = "[\\u4e00-\\u9fa5]";
/**
* 默认使用最小分词
*/
private Analyzer() {
this(false);
}
/**
* 最大分词
* @param maximize 是否最大分词
*/
private Analyzer(boolean maximize) {
this.maximize = maximize;
}
/**
* 初始化
* @param content 内容
* @return 分词器
*/
public static Analyzer instance(String content) {
Analyzer analyzer = new Analyzer();
analyzer.setContent(content);
analyzer.setTokens(new ArrayList<Token>());
if(StringUtils.isNotEmpty(content))
analyzer.chars = content.toCharArray();
return analyzer;
}
/**
* 初始化
* @param content 内容
* @return 分词器
*/
public static Analyzer instanceMaximize(String content) {
Analyzer analyzer = new Analyzer(true);
analyzer.setContent(content);
analyzer.setTokens(new ArrayList<Token>());
if(StringUtils.isNotEmpty(content))
analyzer.chars = content.toCharArray();
return analyzer;
}
/**
* 开始分析
*/
public void analyze() {
if(StringUtils.isEmpty(content))
return;
if(maximize) {
for(;this.index < chars.length; this.index++) {
this.analyzeTokenMaximize();
}
} else {
for(;this.index < chars.length; this.index++) {
this.analyzeToken();
}
}
this. recombination();
}
/**
* 最小分词
*/
private void analyzeToken() {
String word = "";
boolean exact = false; // 判断是否是一个完整匹配的词语
String exactWord = null; // 完整匹配到的词语
String dictionary = null;
List<Dictionary> dictionaries = DictionaryUtils.getInstance().getDictionaries();
for(int index = this.index; index < this.chars.length; index++) {
boolean match = false; // 是否有匹配
word += String.valueOf(this.chars[index]);
for(int i = 0; i < dictionaries.size(); i++) {
dictionary = dictionaries.get(i).getWord();
if(dictionary.equals(word)) {
exact = true;
match = true;
exactWord = word;
break;
} else if (dictionary.startsWith(word)) {
match = true;
// 未排序会导致分词失败
// break;
}
}
if(!match)
break;
}
if(exact) {
Token token = new Token();
token.setWord(exactWord);
token.setExact(true);
this.tokens.add(token);
this.index = this.index + exactWord.length() - 1;
} else {
Token token = new Token();
token.setWord(String.valueOf(this.chars[this.index]));
token.setExact(false);
this.tokens.add(token);
}
}
/**
* 最小分词
*/
private void analyzeTokenMaximize() {
String word = "";
boolean exact = false; // 判断是否是一个完整匹配的词语
String dictionary = null;
List<Dictionary> dictionaries = DictionaryUtils.getInstance().getDictionaries();
for(int index = this.index; index < this.chars.length; index++) {
boolean match = false; // 是否有匹配
word += String.valueOf(this.chars[index]);
for(int i = 0; i < dictionaries.size(); i++) {
dictionary = dictionaries.get(i).getWord();
if(dictionary.equals(word)) {
exact = true;
match = true;
Token token = new Token();
token.setWord(word);
token.setExact(true);
this.tokens.add(token);
if(this.index + word.length() > matchIndex)
matchIndex = this.index + word.length();
break;
} else if(dictionary.startsWith(word)) {
match = true;
// 未排序会导致分词失败
// break;
}
}
if(!match)
break;
}
if(!exact && matchIndex <= this.index) {
Token token = new Token();
token.setWord(String.valueOf(this.chars[this.index]));
token.setExact(false);
this.tokens.add(token);
}
}
/**
* 组装数字、字母
*/
private void recombination() {
StringBuffer tmpWord = new StringBuffer();
List<Token> tokens = new ArrayList<>();
for (Token token : this.getTokens()) {
if(token.getExact() != null && token.getExact()) {
if(tmpWord.length() != 0) {
Token recombineToken = new Token();
recombineToken.setWord(tmpWord.toString());
recombineToken.setExact(false);
tokens.add(recombineToken);
tmpWord.setLength(0);
}
tokens.add(token);
} else {
String word = token.getWord();
if(word.matches(REGEX_LETTER) || word.matches(REGEX_NUMBER)) {
tmpWord.append(token.getWord());
} else {
if(tmpWord.length() != 0) {
if(!tmpWord.toString().matches(REGEX_BLANK)) { // 去掉空白符
Token recombineToken = new Token();
recombineToken.setWord(tmpWord.toString());
recombineToken.setExact(false);
tokens.add(recombineToken);
}
tmpWord.setLength(0);
}
if(!word.matches(REGEX_BLANK)) // 去掉空白符
tokens.add(token);
}
}
}
if(tmpWord.length() != 0) {
Token recombineToken = new Token();
recombineToken.setWord(tmpWord.toString());
recombineToken.setExact(false);
tokens.add(recombineToken);
}
this.setTokens(tokens);
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<Token> getTokens() {
return tokens;
}
public void setTokens(List<Token> tokens) {
this.tokens = tokens;
}
}
注:使用的词库为IK-Analyzer-2012FF的词库,如果是生产环境推荐使用IK分词,本例子仅供学习交流。
下载地址:http://pan.baidu.com/s/1nts0mP7
待优化:
- 数量词
- 词库按照头一个字符分区